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

时间:2014-06-14 14:45:32

标签: c++ c++11 lambda language-lawyer

以下代码

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

给了我一个错误:

  

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

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

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

但是我需要按值捕获它,我不想捕获整个parentItem,因为它很重。任何解决方案?

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

1 个答案:

答案 0 :(得分:12)

  

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


简介

标准规定捕获必须为&=this标识符标识符&开头。

  

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

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

capture:
  identifier
  & identifier
  this
  

由于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](){ ... };

C ++ 11

怎么样?

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

auto& lmb_display_name = parentItem.displayName;

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


注意:您的原始帖子似乎暗示了lambda的捕获列表中引用 R 的名称使lambda包含对 R 引用的引用的引用,这是this snippet可以看到的不是真的。