为什么我不能在lambda中捕获这个by-reference('& this')?

时间:2013-05-01 17:19:05

标签: c++ c++11 lambda

我理解在lambda中捕获this(修改对象属性)的正确方法如下:

auto f = [this] () { /* ... */ };

但我很好奇我所看到的以下特点:

class C {
    public:
        void foo() {
            // auto f = [] () { // this not captured
            auto f = [&] () { // why does this work?
            // auto f = [&this] () { // Expected ',' before 'this'
            // auto f = [this] () { // works as expected
                x = 5;
            };
            f();
        }

    private:
        int x;
};

我感到困惑的奇怪(并希望得到回答)是以下原因:

auto f = [&] () { /* ... */ }; // capture everything by reference

为什么我不能通过引用明确捕获this

auto f = [&this] () { /* ... */ }; // a compiler error as seen above.

2 个答案:

答案 0 :(得分:95)

[&this]不起作用的原因是因为它是语法错误。 lambda-introducer中的每个逗号分隔参数均为capture

capture:
    identifier
    & identifier
    this

您可以看到语法不允许&this。它不被允许的原因是因为你永远不想通过引用捕获this,因为它是一个小的const指针。您只希望按值传递它 - 因此语言不支持通过引用捕获this

要明确捕获this,您可以使用[this]作为lambda-introducer

第一个capture可以是capture-default,即:

capture-default:
    &
    =

这意味着分别通过引用(&)或值(=)自动捕获我使用的任何内容 - 但是this的处理是特殊的 - 在这两种情况下它都被捕获由于前面给出的原因的值(即使默认捕获&,这通常意味着通过引用捕获)。

5.1.2.7/8:

  

出于名称查找(3.4)的目的,确定this(9.3.2)的类型和值并转换id-   使用(*this)(9.3.1)将非静态类成员引用到类成员访问表达式中的表达式,   复合语句[OF THE LAMBDA]在lambda表达的上下文中被考虑。

因此,当使用成员名称时,lambda就好像它是封闭成员函数的一部分一样(比如在你的例子中使用名称x),因此它将生成{{1的“隐式用法”就像成员函数一样。

  

如果lambda-capture包含捕获默认值this,则lambda-capture中的标识符不应为   前面是&。如果lambda-capture包含捕获默认值&,则lambda-capture不应包含   =及其包含的每个标识符都应以this开头。标识符或&不得超过   一次在lambda-capture中。

因此,您可以使用this[this][&][=]作为[&,this]来按值捕获lambda-introducer指针。< / p>

this[&this]格式不正确。在最后一种情况下,gcc宽容地警告[=, this] [=,this]而不是错误。

答案 1 :(得分:3)

因为标准在“捕获”列表中没有&this

N4713 8.4.5.2捕获:

lambda-capture:
    capture-default
    capture-list
    capture-default, capture-list

capture-default:
    &
    =
capture-list:
    capture...opt
    capture-list, capture...opt
capture:
    simple-capture
    init-capture
simple-capture:
    identifier
    &identifier
    this
    * this
init-capture:
    identifier initializer
    &identifier initializer
  
      
  1. 出于lambda捕获的目的,表达式可能引用本地实体,如下所示:

         

    7.3此表达式可能引用* this。

  2.   

因此,标准保证this*this有效,&this无效。此外,捕获this表示捕获*this(这是一个左值,对象本身)通过引用而不是捕获this指针按值