在C ++ lambda表达式中通过值捕获是否需要使用lambda对象复制该值? [英] Does capture by value in a C++ lambda expression require the value to be copied with the lambda object?

查看:89
本文介绍了在C ++ lambda表达式中通过值捕获是否需要使用lambda对象复制该值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Does the standard define what happens with this code?

#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;
}

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

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

Are all features of this output required by the standard?

特别是,如果创建了lambda对象的副本,所有捕获的值也将被复制。但是如果lambda对象通过引用传递,则不会复制捕获的值。

In particular it appears that if a copy of the lambda object is made, all of the captured values are also copied. But if the lambda object is passed by reference none of the captured values are copied. And no copies are made of a captured value just before the function is called, so mutations to the captured value are otherwise preserved between calls.

推荐答案

在调用函数之前,没有副本是由捕获的值组成的,

lambda的类型只是一个类(n3290§5.1.2/ 3),其中有一个执行主体(/ 5)的 operator()一个隐式拷贝构造函数(/ 19)和通过拷贝捕获一个变量相当于将它初始化(/ 21)到这个类的一个非静态数据成员(/ 14),并且该变量的每次使用都被替换为相应的数据成员(/ 17)。在这个转换之后,lambda表达式只会成为这个类的一个实例,并且C ++的一般规则如下。

The type of the lambda is simply a class (n3290 §5.1.2/3), with an operator() which executes the body (/5), and an implicit copy constructor (/19), and capturing a variable by copy is equivalent to copy-initialize (/21) it to a non-static data member (/14) of this class, and each use of that variable is replaced by the corresponding data member (/17). After this transformation, the lambda expression becomes only an instance of this class, and the general rules of C++ follows.

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

That means, your code shall work in the same way as:

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);
}

很明显 callfuncref 在这里。

这篇关于在C ++ lambda表达式中通过值捕获是否需要使用lambda对象复制该值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆