我知道我们必须捕获 lambda 中的 *this 指针才能访问 lambda 中的任何成员变量。现在,为什么我不能仅捕获 lambda 内对象的单个成员?
#include <iostream>
class Foo
{
public:
Foo () : a(5) {}
void func ()
{
[this->a] () { std::cout << a; } ();
}
private:
int a;
};
int main()
{
Foo f;
f.func();
}
上面的代码给我带来了语法错误,
<source>: In member function 'void Foo::func()':
<source>:9:14: error: expected ',' before '->' token
9 | [this->a] () { std::cout << a; } ();
| ^~
<source>:9:14: error: expected identifier before '->' token
我在 Godbolt 中尝试过这个。与 gcc 11.1 的组织
[编辑]我知道有多种方法可以捕获对象的单个成员,但我想了解为什么
this->member
在捕获列表中无效。
但我的问题是为什么这无效
首先要了解的是 lambda 在幕后是如何表达的。编译器将其替换为具有重载
operator()
的匿名类。例如,以下 lambda:
[a](int b){return a + b;}
可以由编译器转换为以下类:
class __lambda_some_random_unique_identifier {
public:
int operator() (int b) const {
return a + b;
}
private:
int a;
};
现在,如果您允许表达式
this->a
出现在捕获列表中,那么应该如何将其转换为类成员?可以说,它可以被称为 a
,但如果你允许表达 this->a
,那么为什么不使用 this->a.size()
(假设 a
是 std::vector
)呢?那怎么命名呢?
由于问题可以通过命名捕获 或 捕获
this
轻松解决,因此没有充分的理由添加处理复杂表达式。
void func ()
{
[a = this->a] () { std::cout << a; } ();
}
您需要指定变量的名称才能在 lambda 中访问它。
编辑:
Lambda 的底层:
执行 lambda 定义时,对于 lambda 捕获的每个变量,都会在 lambda 内部创建该变量的克隆(具有相同的名称)。此时,这些克隆变量是从同名的外部作用域变量初始化的。
所以
[this->a]
没有意义。编译器需要为捕获的变量分配空间,并且为了使该内存可访问,它需要一个名称。
这只是什么语法有效、什么语法无效的问题。您的问题并非特定于
this
。您也无法像这样捕获另一个对象的成员:
struct foo { int x; };
int main() {
foo obj;
foo* f = &obj;
auto l = [f->x](){};
}
虽然这样还可以:
struct foo { int x; };
int main() {
foo obj;
foo* f = &obj;
auto l = [x = f->x](){};
}
如果您打算使用类成员,则公开指针是有意义的
this
class Foo
{
public:
Foo () : a(5) {}
void func ()
{
[this] () { std::cout << a; } ();
}
private:
int a;
};