Member-only story
C++ — Why can’t a const mutable lambda with an auto& parameter be invoked?
Example:
#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
}
There are two interesting things here.
First, a lambda’s call operator (template) is const
by default. If you provide mutable
, then it is not const
. The effect of mutable
on a lambda is solely the opposite of the effect of trailing const
in normal member functions (it does not affect lambda capture, etc.)
So if you look at this:
auto const f3 = [](auto&) mutable {};
static_assert(std::is_invocable_v<decltype(f3), int&>); // failed
This is a const
object, whose call operator template (because it's a generic lambda) is non-const
. So you can't invoke it, for the same reason you can't invoke a non-const
member function on a const
object in any other context. See this other answer.
Second, it has been pointed out that, nevertheless, this works:
auto const f4 = [](int&) mutable {}; // changed auto& to int&
static_assert(std::is_invocable_v<decltype(f4), int&>); // now ok