Lambda捕获列表:在不捕获整个对象的情况下,按值捕获对象的成员字段是不可能的?

Vio*_*ffe 9 c++ lambda language-lawyer c++11

以下代码

void CMainWindow::someMethod(const CLocationsCollection& parentItem)
{
    auto f = [this, parentItem.displayName](){};
}
Run Code Online (Sandbox Code Playgroud)

给我一个错误:

错误C2143:语法错误:'.'之前缺少']'

如果我想parentItem.displayName通过ref 捕获,我会为它创建一个非依赖别名标识符:

const QString& name = parentItem.displayName;
auto f = [this, &name](){}; // Or should it be [this, name] ?
Run Code Online (Sandbox Code Playgroud)

但是我需要通过价值来捕捉它,我不想捕捉整体,parentItem因为它很重.有解决方案吗

PS捕获列表中的名称必须是标识符.parentItem.displayName(作为一个整体)不是一个标识符?为什么编译器无法正确解析?

Fil*_*efp 14

注意:本文中的所有标准参考均来自C++标准草案n3337.


介绍

该标准规定一个捕获必须是&,=,this,的标识符,或一个标识符由preceeded &.

5.1.2 Lambda表达式 [expr.prim.lambda]

capture-list:
  capture ..._opt
  capture-list , capture ..._opt

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

既然parentItem.displayName不是标识符,而是"类成员访问表达式".拒绝你的代码片段时编译器是正确的.

5.2.5p1 类成员访问权限 [expr.ref]

后缀表达式后跟一个点.或箭头->,可选地后跟关键字template(14.2),然后是id-expression,后缀表达式.评估点或箭头之前的后缀表达式; 66该评估的结果与id-expression一起确定整个后缀表达式的结果.


如果只有一种方法用表达式初始化捕获...

C++ 14中,能够使用init-capture来规避手头的问题,看作下面的代码片段.它将使用名称display_name创建一个捕获,使用parentItem.displayName的值初始化.

[display_name = parentItem.displayName](){ ... };
Run Code Online (Sandbox Code Playgroud)

那么C++ 11呢?

遗憾的是,C++ 11中没有这样的功能.因此,问题的解决方案是对数据成员进行本地引用,然后在创建lambda时捕获该引用.

auto& lmb_display_name = parentItem.displayName;

[lmb_display_name](){ ... }; // the lambda will have a copy of `parentItem.displayName`
Run Code Online (Sandbox Code Playgroud)


注意:您的原始帖子似乎暗示lambda的捕获列表中的引用 R的名称将使lambda包含对R引用的引用的引用,这是不正确的,正如此片段所示.