推论lambda捕获类型

Deducing Lambda Capture Types

本文关键字:类型 lambda 推论      更新时间:2023-10-16

我最近发现,通过lambda中的值捕获const对象,这意味着LabMDA的身体内部的变量(即Lambda的数据成员(也是const。例如:

const int x = 0;
auto foo = [x]{
  // x is const int
};

在c 17的草案中,第8.1.5.2节中提到了这种行为:

对于通过复制捕获的每个实体,闭合类型中都声明了一个未命名的非静态数据成员。这 这些成员的声明顺序未指定。这种数据成员的类型是引用类型 如果实体是对对象的引用 是对功能的引用,或相应捕获的实体的类型,否则。一个成员 匿名工会不得被副本捕获。

我希望推论类型的捕获变量与推论自动相同。
是否有充分的理由为被捕获的类型制定不同的类型降低规则?

在您的示例中,由于lambda不是mutable,因此无法修改x,这使函数调用call oterator const。但是,即使lambda是 mutable,它的确是引用的段落在lambda const int中的 x类型。

如果我没记错的话,这是C 11中的故意设计决定,以在Lambda内使用x的行为与封闭范围中使用x相似。也就是说,

void foo(int&);
void foo(const int&);
const int x = 0;
foo(x);  // calls foo(const int&)
auto foo = [x]() mutable {
    foo(x);  // also calls foo(const int&)
};

,这有助于避免错误,例如,例如, 有些代码从具有明确循环到使用lambda的标准库算法。

调用标准库算法。

如果我对此回忆说错了,希望有正确答案的人会介入并写下自己的答案。

不是推理的答案;这里已经有一个全面的答案。

对于那些想知道如何捕获const变量的非const副本的人,您可以使用pinitialiser使用捕获:

const int x = 0;
auto foo = [x = x]() mutable {
    // x is non-const
};

虽然需要C 14。C 11兼容的解决方案是使lambda之外的副本:

const int x = 0;
int copy = x;
auto foo = [copy]() mutable {
    // copy is non-const
};

原因是lambda中的 operator()默认为 const

int main()
{
    const int x = 0;
    auto foo = [x](){}; // main::$_0::operator()() const
    foo();
}

因此您必须使用mutable lambda:

int main()
{
    const int x = 0;
    auto foo = [x=x](){}; // main::$_0::operator()()
    foo();
}

有充分的理由对捕获类型有不同的类型否定规则?

这是故意的决定(以下CWG 756引用了理由/理由(,并且是重写原始Lambda提案的一部分,

  • N2550:lambda表达式和封闭:单态lambdas的措辞(修订4(

  • N2927:C 0x lambdas的新措辞(修订2(

在2009年3月在萨米特举行的会议上,与C 0x有关的许多问题Lambdas由核心工作组(CWG(提出和审查。在决定清晰之后对于大多数此类问题,CWG得出的指示,最好重写本节在Lambdas上实施该方向。本文提出了此重写。

特别是其CWG 756的分辨率[重点 mine]:

  • CWG 756.闭合对象成员删除CV-CALIFIFICAL

[...]考虑以下示例:

void f() {
  int const N = 10;
  [=]() mutable { N = 30; }  // Okay: this->N has type int, not int const.
  N = 20;  // Error.
}

也就是说,是闭合对象的成员的n不是const,即使捕获的变量是const。这似乎很奇怪, as捕获基本上是捕获本地环境的一种手段避免终身问题的方式。更认真地,类型的更改表示声明,超载分辨率和模板的结果参数扣除应用于lambda内的捕获变量表达可能与包含包含的范围的表达方式不同lambda表达式,它可能是错误的微妙来源。