【发布时间】:2019-10-08 12:29:25
【问题描述】:
我试图理解/澄清在将捕获传递给 lambda 时生成的代码代码,尤其是在 C++14 中添加的通用初始化捕获中。
给出下面列出的以下代码示例,这是我目前对编译器将生成什么的理解。
案例1:按值捕获/默认按值捕获
int x = 6;
auto lambda = [x]() { std::cout << x << std::endl; };
相当于:
class __some_compiler_generated_name {
public:
__some_compiler_generated_name(int x) : __x{x}{}
void operator()() const { std::cout << __x << std::endl;}
private:
int __x;
};
所以有多个副本,一个复制到构造函数参数中,一个复制到成员中,这对于向量等类型来说会很昂贵。
案例2:引用捕获/默认引用捕获
int x = 6;
auto lambda = [&x]() { std::cout << x << std::endl; };
相当于:
class __some_compiler_generated_name {
public:
__some_compiler_generated_name(int& x) : x_{x}{}
void operator()() const { std::cout << x << std::endl;}
private:
int& x_;
};
参数是引用,成员是引用,所以没有副本。非常适合矢量等类型。
案例 3:
广义初始化捕获
auto lambda = [x = 33]() { std::cout << x << std::endl; };
我的理解是这在某种意义上类似于案例 1 将其复制到成员中。
我的猜测是编译器生成的代码类似于...
class __some_compiler_generated_name {
public:
__some_compiler_generated_name() : __x{33}{}
void operator()() const { std::cout << __x << std::endl;}
private:
int __x;
};
如果我有以下情况:
auto l = [p = std::move(unique_ptr_var)]() {
// do something with unique_ptr_var
};
构造函数会是什么样子?它是否也将其移动到成员中?
【问题讨论】:
-
@rafix07 在这种情况下,生成的洞察代码甚至无法编译(它尝试复制初始化参数中的唯一 ptr 成员)。 cppinsights 对于获取一般要点很有用,但它显然无法在这里回答这个问题。
-
您似乎假设将 lambda 转换为函子作为编译的第一步,或者您只是在寻找等效的代码(即相同的行为)?特定编译器生成代码的方式(以及它生成的代码)将取决于编译器、版本、体系结构、标志等。那么,您是否要求特定平台?如果不是,那么您的问题无法真正回答。除了实际生成的代码可能会比您列出的仿函数更有效(例如,内联构造函数、避免不必要的副本等)。
-
如果您对 C++ 标准对此的规定感兴趣,请参阅 [expr.prim.lambda]。在这里总结为一个答案太多了。