在C++ lambda表达式中按值捕获是否需要使用lambda对象复制值?

Omn*_*ous 4 c++ lambda c++11

标准是否定义了此代码会发生什么?

#include <iostream>

template <typename Func>
void callfunc(Func f)
{
   ::std::cout << "In callfunc.\n";
    f();
}

template <typename Func>
void callfuncref(Func &f)
{
   ::std::cout << "In callfuncref.\n";
    f();
}

int main()
{
    int n = 10;
    // n is captured by value, and the lambda expression is mutable so
    // modifications to n are allowed inside the lambda block.
    auto foo = [n]() mutable -> void {
       ::std::cout << "Before increment n == " << n << '\n';
       ++n;
       ::std::cout << "After increment n == " << n << '\n';
    };
    callfunc(foo);
    callfunc(foo);
    callfuncref(foo);
    callfunc(foo);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

用g ++输出的是:

$ ./a.out 
In callfunc.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 10
After increment n == 11
In callfuncref.
Before increment n == 10
After increment n == 11
In callfunc.
Before increment n == 11
After increment n == 12
Run Code Online (Sandbox Code Playgroud)

标准是否需要此输出的所有功能?

特别是看起来,如果创建了lambda对象的副本,则还会复制所有捕获的值.但是,如果通过引用传递lambda对象,则不会复制捕获的值.并且在调用函数之前不会复制捕获的值,因此在调用之间保留对捕获值的突变.

ken*_*ytm 9

lambda的类型只是一个类(n3290§5.1.2/ 3),其中一个operator()执行主体(/ 5),一个隐式复制构造函数(/ 19),并通过复制捕获一个变量等同于复制-initialize(/ 21)它到该类的非静态数据成员(/ 14),并且该变量的每次使用都被相应的数据成员(/ 17)替换.在此转换之后,lambda表达式只变为此类的一个实例,并遵循C++的一般规则.

这意味着,您的代码应以与以下相同的方式工作:

int main()
{
    int n = 10;

    class __Foo__           // §5.1.2/3
    {
        int __n__;          // §5.1.2/14
    public:
        void operator()()   // §5.1.2/5
        {
            std::cout << "Before increment n == " << __n__ << '\n';
            ++ __n__;       // §5.1.2/17
            std::cout << "After increment n == " << __n__ << '\n';
        }
        __Foo__() = delete;
        __Foo__(int n) : __n__(n) {}
      //__Foo__(const __Foo__&) = default;  // §5.1.2/19
    }
    foo {n};                // §5.1.2/21

    callfunc(foo);
    callfunc(foo);
    callfuncref(foo);
    callfunc(foo);
}
Run Code Online (Sandbox Code Playgroud)

显而易见的是callfuncref这里有什么.

  • @Omnifarious:移动构造函数:"可能"(§5.1.2/ 19:"并且可能有一个隐式声明的移动构造函数").lambda没有任何赋值运算符,它们被删除. (3认同)