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

Ant*_*ile 74 c++ lambda c++11

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

auto f = [this] () { /* ... */ };
Run Code Online (Sandbox Code Playgroud)

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

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;
};
Run Code Online (Sandbox Code Playgroud)

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

auto f = [&] () { /* ... */ }; // capture everything by reference
Run Code Online (Sandbox Code Playgroud)

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

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

And*_*zos 100

原因[&this]不起作用是因为它是语法错误.每个逗号分隔的参数lambda-introducercapture:

capture:
    identifier
    & identifier
    this
Run Code Online (Sandbox Code Playgroud)

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

要捕获this明确可以使用[this]lambda-introducer.

第一个capture可以capture-default是:

capture-default:
    &
    =
Run Code Online (Sandbox Code Playgroud)

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

5.1.2.7/8:

出于名称查找(3.4)的目的,确定this(9.3.2)的类型和值,并使用(*this)(9.3.1)将引用非静态类成员的id-表达式转换为类成员访问表达式,复合语句[OF LAMBDA]被认为是在lambda表达的背景下.

所以lambda在使用成员名称时就好像它是封闭成员函数的一部分(就像在你的例子中使用名称一样x),因此它将this像成员函数一样生成"隐式用法" .

如果lambda-capture包含捕获默认值,则&lambda-capture中的标识符不得以其为前缀&.如果lambda-capture包含一个capture-default =,那么lambda-capture不应该包含, this并且它包含的每个标识符都应该在前面&.一个标识符或this在lambda-capture中不会出现多次.

所以,你可以使用[this],[&],[=][&,this]作为lambda-introducer捕获this的价值指针.

然而[&this],[=, this]形象不对称.在最后一种情况GCC forgivingly警告的[=,this]那个explicit by-copy capture of ‘this’ redundant with by-copy capture default,而不是错误.

  • @KonradRudolph:块级构造不会将指向它们所使用的对象的指针神奇地复制到一个新的不可见匿名类型中,该类型可以在封闭范围内存活 - 只需使用表达式中的对象名称即可.Lambda捕获更是一项危险的业务. (8认同)
  • @KonradRudolph我会说"使用`[&]`如果你正在做一些像创建一个块来传递给一个控制结构",但明确捕获你是否正在生成一个将用于不太简单目的的lambda .如果lambda将比目前的范围更长,那么[和]`是一个可怕的想法.但是,lambdas的许多用法只是将块传递给控制结构的方法,并且块不会比它在范围中创建的块寿命更长. (5认同)
  • @KonradRudolph:如果你想按价值和其他人参考来捕捉一些东西怎么办?或者想要非常明确地捕捉到什么? (3认同)
  • @KonradRudolph:这是一个安全功能.您可能会意外捕获您不想要的名称. (2认同)
  • @Ruslan:不,`this`是关键字,`this`不是标识符. (2认同)

陳 力*_*陳 力 7

因为标准&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
Run Code Online (Sandbox Code Playgroud)
  1. 出于 lambda 捕获的目的,表达式可能会引用本地实体,如下所示:

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

因此,标准的保障this*this有效,并且&this是无效的。此外,捕获this意味着通过引用捕获*this(这是一个左值,对象本身),而不是通过值捕获指针!this