为什么不能调用带有 auto& 参数的 const mutable lambda?
Why can't a const mutable lambda with an auto& parameter be invoked?
#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
}
见demo
为什么 const 可变 lambda 不能接受引用参数?
出于同样的原因,您会收到错误消息:
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 实例上调用非常量方法。 Lambdas 得到了默认的常量,所以如果没有 mutable
,operator()
就是 const
。对于 mutable
,operator()
是一个非常量方法,您不能在 const f3;
上调用它
这里有两件有趣的事情。
首先,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
still 有一个 non-const 调用操作符。你不能调用它,因为 f4
是一个常量对象。
但是
没有捕获的 lambda 还有另一个有趣的方面:它们有一个到函数指针类型的转换函数。也就是说,我们通常认为 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
中的任何一个 surrogate call functions - 是否有任何函数指针可以将 f
转换为,然后调用。
在这种情况下,你可以!您可以将 f4
转换为 void(*)(int&)
并且可以使用 int&
.
调用该函数指针
但这仍然意味着 f4
的调用运算符不是 const,因为您声明它是可变的。它并没有说明你是否可以让 mutable
lambda 接受参考参数。
#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
}
见demo
为什么 const 可变 lambda 不能接受引用参数?
出于同样的原因,您会收到错误消息:
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 实例上调用非常量方法。 Lambdas 得到了默认的常量,所以如果没有 mutable
,operator()
就是 const
。对于 mutable
,operator()
是一个非常量方法,您不能在 const f3;
这里有两件有趣的事情。
首先,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
still 有一个 non-const 调用操作符。你不能调用它,因为 f4
是一个常量对象。
但是
没有捕获的 lambda 还有另一个有趣的方面:它们有一个到函数指针类型的转换函数。也就是说,我们通常认为 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
中的任何一个 surrogate call functions - 是否有任何函数指针可以将 f
转换为,然后调用。
在这种情况下,你可以!您可以将 f4
转换为 void(*)(int&)
并且可以使用 int&
.
但这仍然意味着 f4
的调用运算符不是 const,因为您声明它是可变的。它并没有说明你是否可以让 mutable
lambda 接受参考参数。