如果我将可变 lambda 作为 const 引用传递给函数,会发生什么情况?

What will happen if I pass a mutable lambda to a function as const reference?

当我将可变 lambda 作为 const 引用传递时,代码实际上做了什么?

为什么编译器不报错,这是未定义的操作吗?

为什么 f1 和 f2 不同,f1 使用 std::function<void()> 而 f2 使用 auto

我发现了一个类似的问题,但我还是不太明白

#include <iostream>
#include <functional>

void call(std::function<void()> const & cb) {
    cb();
    cb();
}

int main() {
    std::function<void()> f1 = [a = 0] () mutable {
        std::cout << ++a << std::endl;
    };
    call(f1); // prints 1 2
    call(f1); // prints 3 4

    auto f2 = [a = 0] () mutable {
        std::cout << ++a << std::endl;
    };
    call(f2); // prints 1 2
    call(f2); // prints 1 2
}

https://godbolt.org/z/765endY7c

在第一种情况下,call(f1) 的两个调用都使用相同的 std::function<void()> 实例。

在第二种情况下,call(f2); 隐式转换形式 lambda 到 std::function<void()> 启动并创建相应的临时对象。所以第二次调用使用临时对象的新副本。

Try transform this code in cppinsights 以查看更多详细信息。

int main()
{
    
  class __lambda_10_32
  {
    public: 
    inline /*constexpr */ void operator()()
    {
      std::cout.operator<<(++a).operator<<(std::endl);
    }
    
    private: 
    int a;
    public: 
    // inline /*constexpr */ __lambda_10_32(const __lambda_10_32 &) noexcept = default;
    // inline /*constexpr */ __lambda_10_32(__lambda_10_32 &&) noexcept = default;
    __lambda_10_32(const int & _a)
    : a{_a}
    {}
    
  };
  
  std::function<void ()> f1 = std::function<void ()>(__lambda_10_32{0});
  call(f1);
  call(f1);
    
  class __lambda_16_15
  {
    public: 
    inline /*constexpr */ void operator()()
    {
      std::cout.operator<<(++a).operator<<(std::endl);
    }
    
    private: 
    int a;
    public: 
    // inline /*constexpr */ __lambda_16_15(const __lambda_16_15 &) noexcept = default;
    // inline /*constexpr */ __lambda_16_15(__lambda_16_15 &&) noexcept = default;
    __lambda_16_15(const int & _a)
    : a{_a}
    {}
    
  };
  
  __lambda_16_15 f2 = __lambda_16_15{0};
  call(std::function<void ()>(__lambda_16_15(f2)));
  call(std::function<void ()>(__lambda_16_15(f2)));
  return 0;
}