Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is mutable lambda converted to function pointer instead of calling operator()?

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.

like image 809
Dr. Gut Avatar asked Oct 13 '25 01:10

Dr. Gut


1 Answers

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 expression E(args) has class type cv T, then

  • The function-call operators of T are obtained by ordinary lookup of the name operator() 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 of T (unless hidden), whose cv-qualifiers are the same or greater than T'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.

like image 104
Remy Lebeau Avatar answered Oct 14 '25 21:10

Remy Lebeau