Have a look at the code example listed below, I tested it with Compiler explorer (using gcc and clang) and it works and prints out the (expected) output of 200.
What I am trying to figure out: why exactly is this valid C . Or is it not?
Here, I'm using the using
keyword to define an alias (instead of a typedef
) for the function type ft
, which describes functions that take an int
as argument and return an int
(ft
is a function type, not a function pointer type!). The equivalent typedef
syntax is typedef int ft(int);
. Since the C standard says that for every typedef
there is an equivalent form using the using
syntax, it is clear that using ft = int(int)
is a well-defined way to specify this function type.
Now comes the interesting part: I use the type ft
to specify the argument type of another function (print_it
), and then call it, passing a lambda function. My question is: where/how does the C standard say that this should actually work? I think it is a wonderfully simple way to pass lambdas around. That this works is not clear to me, as a lambda is really a functor, not a function in the strict sense. So I think it is not clear that this lambda matches the type ft
and therefore can be passed to print_it
(if ft
was defined to be std::function<int(int)>
it would be clear though).
The code example:
#include <iostream>
using ft = int(int);
void print_it (ft f, int a)
{
std::cout << f(a) << std::endl;
}
int main ()
{
auto my_lambda = [] (int a) -> int { return 2 * a; };
print_it (my_lambda, 100);
return (0);
}
CodePudding user response:
My question is: where/how does the C standard say that this should actually work?
This is specified in [expr.prim.lambda.closure]/7, which specifies that a lambda's closure type has a conversion function to a function pointer type matching the lambda's parameter and return types if the lambda is non-generic and doesn't have any capture. Calling through this function pointer basically behaves as if the lambda body was just a normal function to which the pointer points, which is possible because there are no captures which could give the lambda a state that a normal function can't have.
This applies here and you are using the conversion operator to implicitly convert the lambda object to a function pointer when passing it to print_it
. This works since the lambda's parameter and return type matches the ft
type and a function type used as type of a function parameter is adjusted to a pointer-to-function type instead. (See [dcl.fct]/5 for the last part.)
For generic lambdas there is a conversion function template (see the following standard paragraph). For lambdas with a capture there is no such conversion function and therefore this wouldn't work for them.
CodePudding user response:
This only works because your lambda does not capture. A capture-less lambda can be converted to a C-style function pointer but a captureing lambda cannot.