C++ Lambdas:"可变"和"按引用捕获"之间的区别

Seb*_*ach 65 c++ lambda c++11

在C++中,你可以像这样声明lambdas:

int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '\n'; };
auto b = [&]()         { ++x; std::cout << x << '\n'; };
Run Code Online (Sandbox Code Playgroud)

两个都让我修改x,那有什么区别?

Seb*_*ach 85

怎么了

第一个只修改自己的副本,xx保持外部不变.第二个将修改外部x.

尝试每个后添加一个print语句:

a();
std::cout << x << "----\n";
b();
std::cout << x << '\n';
Run Code Online (Sandbox Code Playgroud)

预计这将打印:

6
5
----
6
6
Run Code Online (Sandbox Code Playgroud)

为什么

考虑lambda可能会有所帮助

[...]表达式提供了创建简单函数对象的简洁方法

(参见标准的[expr.prim.lambda])

他们有

[...]公共内联函数调用操作符[...]

它被声明为const成员函数,但仅限于

[...]当且仅当lambda表达式的parameter-declaration-clause未被跟随时mutable

你可以想到

    int x = 5;
    auto a = [=]() mutable { ++x; std::cout << x << '\n'; };

==>

    int x = 5;

    class __lambda_a {
        int x;
    public:
        __lambda_a () : x($lookup-one-outer$::x) {}
        inline void operator() { ++x; std::cout << x << '\n'; }     
    } a;
Run Code Online (Sandbox Code Playgroud)

    auto b = [&]()         { ++x; std::cout << x << '\n'; };

==>

    int x = 5;

    class __lambda_b {
        int &x;
    public:
        __lambda_b() : x($lookup-one-outer$::x) {}
        inline void operator() const { ++x; std::cout << x << '\n'; }         
        //                     ^^^^^
    } b;
Run Code Online (Sandbox Code Playgroud)

问:但如果它是一个const功能,为什么我还能改变x

答:你只是在改变外面x.lambda自己x是一个引用,操作++x不会修改引用,而是修改引用的值.

这是有效的,因为在C++中,指针/引用的常量不会改变通过它看到的指针/引用的常量.

  • @ AnoopK.Prabhu:在最后一个例子中,`const`实际上没有区别.你_always_通过引用变异引用.但是举另一个例子:`int main(){int x; auto a = [=](){++ x; }; }`.g ++会给出一条错误信息,因为`[=]`表示生成的函数对象获取自己的成员变量`x`,但缺少`mutable`意味着生成一个`const`成员函数调用运算符,因此`x`不可分配. (3认同)
  • 真正的问题是为什么与C++中的其他所有内容相比,反转惯例.`mutable`限定应该是默认的,`const`规范应该是显式的. (3认同)