为什么 lambda 的调用运算符隐式为 const?
Why is a lambda's call-operator implicitly const?
我在下面的函数中有一个小 "lambda expression":
int main()
{
int x = 10;
auto lambda = [=] () { return x + 3; };
}
下面是为上述 lambda 表达式生成的 "anonymous closure class"。
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。为什么标准委员会默认const
?
Unless the keyword mutable
was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside this operator()
在你的例子中,没有任何东西,通过副本捕获,是可以修改的。
我想,如果你把东西写成
int x = 10;
auto lambda = [=] () mutable { x += 3; return x; };
const
应该消失
-- 编辑--
OP 精确
I already knew that adding mutable will solve the issue. The question is that I want to understand the reason behind making the lambda immutable by default.
我不是语言律师,但这在我看来是显而易见的:如果你让 operator()
不是 const
,你就不能像
template <typename F>
void foo (F const & f)
{ f(); }
// ...
foo([]{ std::cout << "lambda!" << std::endl; });
我的意思是...如果 operator()
不是 const
,您不能使用 lambda 将它们作为 const
引用传递。
当不是严格需要时,应该是一个不可接受的限制。
在 open-std.org 上找到了 Herb Sutter paper,其中讨论了这个问题。
The odd couple: Capture by value’s injected const and quirky mutable
Consider this strawman example, where the programmer captures a local variable by value and tries to modify the captured value (which is a member variable of the lambda object):
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’
This feature appears to have been added out of a concern that the user might not realize he got a copy, and in particular that since lambdas are copyable he might be changing a different lambda’s copy.
以上引用和示例说明了为什么标准委员会 可能 将其设为 const
并要求 mutable
对其进行更改。
我认为,这只是为了避免在 lambda 中的变量引用的不是最初捕获的内容时造成混淆。从词法上讲,这样的变量就好像在其 "original" 的范围内一样。复制主要是为了允许延长对象的生命周期。当捕获不是通过复制时,它指的是原始对象并将修改应用于原始对象,并且不会因为两个不同的对象(其中一个是隐式引入的)而混淆,并且它是 lambda 的 const 函数调用运算符所允许的。
我在下面的函数中有一个小 "lambda expression":
int main()
{
int x = 10;
auto lambda = [=] () { return x + 3; };
}
下面是为上述 lambda 表达式生成的 "anonymous closure class"。
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。为什么标准委员会默认const
?
Unless the keyword
mutable
was used in the lambda-expression, the function-call operator is const-qualified and the objects that were captured by copy are non-modifiable from inside thisoperator()
在你的例子中,没有任何东西,通过副本捕获,是可以修改的。
我想,如果你把东西写成
int x = 10;
auto lambda = [=] () mutable { x += 3; return x; };
const
应该消失
-- 编辑--
OP 精确
I already knew that adding mutable will solve the issue. The question is that I want to understand the reason behind making the lambda immutable by default.
我不是语言律师,但这在我看来是显而易见的:如果你让 operator()
不是 const
,你就不能像
template <typename F>
void foo (F const & f)
{ f(); }
// ...
foo([]{ std::cout << "lambda!" << std::endl; });
我的意思是...如果 operator()
不是 const
,您不能使用 lambda 将它们作为 const
引用传递。
当不是严格需要时,应该是一个不可接受的限制。
在 open-std.org 上找到了 Herb Sutter paper,其中讨论了这个问题。
The odd couple: Capture by value’s injected const and quirky mutable
Consider this strawman example, where the programmer captures a local variable by value and tries to modify the captured value (which is a member variable of the lambda object):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’
This feature appears to have been added out of a concern that the user might not realize he got a copy, and in particular that since lambdas are copyable he might be changing a different lambda’s copy.
以上引用和示例说明了为什么标准委员会 可能 将其设为 const
并要求 mutable
对其进行更改。
我认为,这只是为了避免在 lambda 中的变量引用的不是最初捕获的内容时造成混淆。从词法上讲,这样的变量就好像在其 "original" 的范围内一样。复制主要是为了允许延长对象的生命周期。当捕获不是通过复制时,它指的是原始对象并将修改应用于原始对象,并且不会因为两个不同的对象(其中一个是隐式引入的)而混淆,并且它是 lambda 的 const 函数调用运算符所允许的。