这里有两件有趣的事情。
首先,lambda 的调用运算符(模板)是const
默认情况下。如果您提供mutable
,那么它不是const
。的效果mutable
在 lambda 上是solely与尾随效果相反const
在普通成员函数中(它不影响 lambda 捕获等)
所以如果你看看这个:
auto const f3 = [](auto&) mutable {};
static_assert(std::is_invocable_v<decltype(f3), int&>); // failed
这是一个const
对象,其调用运算符模板(因为它是通用 lambda)是非const
。所以你不能调用它,出于同样的原因你不能调用非const
上的成员函数const
任何其他上下文中的对象。看这个另一个答案 https://stackoverflow.com/a/70309342/2069064.
其次,有人指出,尽管如此,这是有效的:
auto const f4 = [](int&) mutable {}; // changed auto& to int&
static_assert(std::is_invocable_v<decltype(f4), int&>); // now ok
This is not编译器错误。Nor是不是说明我刚才说的都是错的。f4
still has a 非常量呼叫接线员。你不能调用它,因为f4
是一个常量对象。
However.
没有捕获的 lambda 表达式还有另一个有趣的方面:它们有一个到函数指针类型的转换函数。也就是说,我们通常会想到 lambdaf4
看起来像这样:
struct __unique_f4 {
auto operator()(int&) /* not const */ { }
};
而且,如果这就是整个故事,const __unique_f4
确实不可调用int&
。但它actually看起来像这样:
struct __unique_f4 {
auto operator()(int&) /* not const */ { }
// conversion function to the appropriate function
// pointer type
operator void(*)(int&)() const { /* ... */ }
};
当你调用一个对象时,我们有这样的规则,比如f(x)
,你不仅考虑f
的呼叫操作员——那些被命名的成员operator()
——但你也考虑其中的任何一个f
's 代理调用函数 https://eel.is/c++draft/over#def:surrogate_call_function-- 是否有可以转换的函数指针f
到,然后调用。
在这种情况下,你可以!你可以转换f4
to a void(*)(int&)
并且该函数指针可以通过以下方式调用int&
.
但这仍然意味着f4
的调用运算符不是 const,因为您声明它是可变的。它并没有说明你是否可以拥有mutable
lambda 接受参考参数。