为什么非可变lambda中的字段在捕获常量值或常量引用时使用“const”?
正如问题lambda capture by value mutable 中所见,它不适用于 const &? , 当const T&使用其名称或[=]可变 lambda捕获类型的值时,隐藏类中的字段获取类型const T。可以争论的是,这对于可变 lambda 来说是正确的做法。
但是为什么对非可变 lambda 也这样做呢?在非可变 lambda 表达式中,operator()(...)is 被声明const,因此无论如何它都不能修改捕获的值。
当我们移动 lambda 时,例如将它包装在std::function.
请参阅以下两个示例:
#include <cstdio>
#include <functional>
std::function<void()> f1, f2;
struct Test {
Test() {puts("Construct");}
Test(const Test& o) {puts("Copy");}
Test(Test&& o) {puts("Move");}
~Test() {puts("Destruct");}
};
void set_f1(const Test& v) {
f1 = [v] () {}; // field type in lambda object will be "const Test"
}
void set_f2(const Test& v) {
f2 = [v = v] () {}; // field type in lambda object will be "Test"
}
int main() {
Test t;
puts("set_f1:");
set_f1(t);
puts("set_f2:");
set_f2(t);
puts("done");
}
我们得到以下编译器生成的 lambda 类:
class set_f1_lambda {
const Test v;
public:
void operator()() const {}
};
class set_f2_lambda {
Test v;
public:
void operator()() const {}
};
该程序打印以下内容(使用 gcc 或 clang):
Construct
set_f1:
Copy
Copy
Copy
Destruct
Destruct
set_f2:
Copy
Move
Move
Destruct
Destruct
done
Destruct
Destruct
Destruct
v在第一个示例中,该值被复制不少于 3 次set_f1。
在第二个示例中set_f2,唯一的副本是在捕获值时(如预期的那样)。使用两次移动这一事实是 libstdc++ 中的一个实现细节。当按值将函子传递给内部函数时,第一步发生在operator=instd::function内部(为什么此函数签名不使用按引用传递?)。第二个移动发生在移动构造最终堆分配的函子时。
但是,如果字段是 const(因为这样的构造函数在窃取其内容后无法“清除”const 变量)。这就是为什么必须将复制构造函数用于此类字段的原因。
所以对我来说,像const在非可变 lambdas 中一样捕获值似乎只有负面影响。我是否遗漏了一些重要的东西,或者它只是通过这种方式标准化以某种方式使标准更简单?
THE END
二维码