关于c ++ 11:C ++ Lambdas:“可变”和“按引用捕获”之间的区别

C++ Lambdas: Difference between “mutable” and capture-by-reference

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

1
2
3
4
5
int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '
'
; };
auto b = [&]()         { ++x; std::cout << x << '
'
; };

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


怎么了

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

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

1
2
3
4
5
6
a();
std::cout << x <<"----
"
;
b();
std::cout << x << '
'
;

预计这将打印:

1
2
3
4
5
6
5
----
6
6

为什么

考虑lambda可能会有所帮助

[...] expressions provide a concise way to create simple function objects

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

他们有

[...] a public inline function call operator [...]

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

[...] if and only if the lambda expression’s parameter-declaration-clause is not followed by mutable

你可以想到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    int x = 5;
    auto a = [=]() mutable { ++x; std::cout << x << '
'
; };

==>

    int x = 5;

    class __lambda_a {
        int x;
    public:
        __lambda_a () : x($lookup-one-outer$::x) {}
        inline void operator() { ++x; std::cout << x << '
'
; }    
    } a;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    auto b = [&]()         { ++x; std::cout << x << '
'
; };

==>

    int x = 5;

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

问:但如果它是const函数,为什么我仍然可以改变x

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

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