我在以下函数中有一个小的“ lambda表达式”:
int main()
{
int x = 10;
auto lambda = [=] () { return x + 3; };
}
下面是为上述lambda表达式生成的“匿名闭包类”。
int main()
{
int x = 10;
class __lambda_3_19
{
public: inline /*constexpr */ int operator()() const
{
return x + 3;
}
private:
int x;
public: __lambda_3_19(int _x) : x{_x}
{}
};
__lambda_3_19 lambda = __lambda_3_19{x};
}
由编译器生成的闭包的“ operator()”是隐式常量。为什么标准委员会默认将其设置为const
?
答案 0 :(得分:18)
在open-std.org上由Herb Sutter找到了paper,讨论了此事。
奇怪的一对:按值注入的常量和古怪的可变性来捕获
考虑以下示例,程序员通过值捕获局部变量并尝试修改捕获的值(它是lambda对象的成员变量):int val = 0; auto x = [=]( item e ) // look ma, [=] means explicit copy { use( e, ++val ); }; // error: count is const, need ‘mutable’ auto y = [val]( item e ) // darnit, I really can’t get more explicit { use( e, ++val ); }; // same error: count is const, need ‘mutable’
添加此功能的原因是担心用户可能不会意识到自己获得了副本,尤其是由于Lambda是可复制的,因此他可能会更改其他Lambda的副本。 < / p>
以上引用和示例说明了为什么标准委员会可能默认将其设置为const
,并要求mutable
对其进行更改。
答案 1 :(得分:9)
除非在lambda表达式中使用了关键字
mutable
,否则函数调用运算符是const限定的,并且从复制operator()
内部获取的被复制捕获的对象是不可修改的>
对于您来说,复制捕获的内容是不可修改的。
我想,如果你写的东西是
int x = 10;
auto lambda = [=] () mutable { x += 3; return x; };
const
应该消失
-编辑-
OP精确
我已经知道添加可变变量可以解决此问题。问题是我想了解默认情况下使lambda不可变的原因。
我不是语言律师,但我看来这很明显:如果您使operator()
而不是const
,您将无法像
template <typename F>
void foo (F const & f)
{ f(); }
// ...
foo([]{ std::cout << "lambda!" << std::endl; });
我的意思是...如果operator()
不是const
,则不能使用将它们作为const
引用传递的lambda。
当不是严格需要时,应该是一个不能接受的限制。
答案 2 :(得分:0)
我认为,当lambda中的变量不引用最初捕获的内容时,只是为了避免混淆。在词法上,这样的变量就好像在其“原始”范围内一样。复制主要是为了延长对象的寿命。当捕获不是复制时,它指的是原始文件,并且对原始文件进行了修改,并且由于两个不同的对象(其中一个对象是隐式引入的)而不会引起混淆,并且lambda的const函数调用运算符允许这样做。 / p>