#include <type_traits>
int main()
{
auto f1 = [](auto&) mutable {};
static_assert(std::is_invocable_v<decltype(f1), int&>); // ok
auto const f2 = [](auto&) {};
static_assert(std::is_invocable_v<decltype(f2), int&>); // ok
auto const f3 = [](auto&) mutable {};
static_assert(std::is_invocable_v<decltype(f3), int&>); // failed
}请参阅演示
为什么一个不可变的λ不能接受一个引用参数?
发布于 2021-12-10 19:25:30
这里有两件有趣的事情。
首先,默认情况下,lambda的调用操作符(模板)是const。如果您提供mutable,那么它不是const。mutable对lambda的影响与正常成员函数中跟踪const的效果完全相反(它不影响lambda捕获等)。
所以如果你看看这个:
auto const f3 = [](auto&) mutable {};
static_assert(std::is_invocable_v<decltype(f3), int&>); // failed这是一个const对象,其调用操作符模板(因为它是一个通用的lambda)是非const的。因此,您不能调用它,同样的原因是,您不能在任何其他上下文中调用const对象上的非const成员函数。见另一个答案。
第二,有人指出,这是可行的:
auto const f4 = [](int&) mutable {}; // changed auto& to int&
static_assert(std::is_invocable_v<decltype(f4), int&>); // now ok这不是编译器的错误。也不意味着我刚才说的是错的。f4仍然有一个非const呼叫运营商.因为f4是一个const对象,所以不能调用它。
然而。
lambdas还有一个有趣的方面没有捕获:它们有一个将函数转换为函数指针类型的函数。也就是说,我们通常认为lambda f4如下所示:
struct __unique_f4 {
auto operator()(int&) /* not const */ { }
};而且,如果这是整个故事的话,const __unique_f4确实不能用int&来调用。但实际上看起来是这样的:
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的代理呼叫函数中的任何一个--是否有任何函数指针可以将f转换为,然后调用。
在这种情况下,你可以!您可以将f4转换为void(*)(int&),并且可以用int&调用该函数指针。
但这仍然意味着f4的呼叫运算符不是const,因为您声明它是可变的,而且它也没有说明是否可以让mutable lambda接受引用参数。
发布于 2021-12-10 19:09:17
由于同样的原因,您会得到一个错误:
struct foo {
void operator()(){}
};
int main() {
const foo f;
f();
}错误是:
<source>:7:5: error: no matching function for call to object of type 'const foo'
f();
^
<source>:2:10: note: candidate function not viable: 'this' argument has type 'const foo', but method is not marked const
void operator()(){}
^因为不能在const实例上调用非const方法。Lambda获得了默认的常数,因此如果没有mutable,operator()就是const。对于mutable,operator()是一个不能调用const f3;的非const方法。
https://stackoverflow.com/questions/70309251
复制相似问题