From cppinsights we see how in the following code the line lambda();
is interpreted by the language:
const auto lambda = [] () mutable {};
void foo()
{
lambda();
}
One would naively think, that this line calls the lambda's (non-const) operator()
, which in turn doesn't compile. But, instead of this, the compiler converts the non-capturing lambda to a function pointer, calls the function pointer, and accepts the code.
What's the purpose of this conversion? To me, it would be more logical, if this would be rejected. There is no sign, that the programmer intended this conversion. The language does this on its own.
Note, that the conversion happens only in the above case, where calling lambda.operator()()
would discard qualifiers. It does not happen (i.e., operator()
is called directly), if lambda
is not const
, or operator()
is not marked mutable
.
Declaring a lambda as mutable
means its operator()
can modify captured variables, which means the operator()
can't be const
. But lambda
is a const
object, so a non-const operator()
can't be called on it (and indeed, if you try, the compiler will report an error).
However, overload resolution accepts a class type that has a conversion operator to a function pointer:
Call to a class object
If
E
in a function call expressionE(args)
has class typecv T
, then
The function-call operators of
T
are obtained by ordinary lookup of the nameoperator()
in the context of the expression(E).operator()
, and every declaration found is added to the set of candidate functions.For each non-explicit user-defined conversion function in
T
or in a base ofT
(unless hidden), whose cv-qualifiers are the same or greater thanT
's cv-qualifiers, and where the conversion function converts to:
- pointer-to-function
- reference-to-pointer-to-function
- reference-to-function
then a surrogate call function with a unique name whose first parameter is the result of the conversion, the remaining parameters are the parameter-list accepted by the result of the conversion, and the return type is the return type of the result of the conversion, is added to the set of candidate functions. If this surrogate function is selected by the subsequent overload resolution, then the user-defined conversion function will be called and then the result of the conversion will be called.
And, since a lambda is a class type, and a non-capturing lambda is implicitly convertible to a pointer-to-function, the compiler converts the lambda
object into a function pointer and then calls the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With