Home > Net >  Why can a C function type alias be used to pass a lambda to a function?
Why can a C function type alias be used to pass a lambda to a function?

Time:07-29

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.

  •  Tags:  
  • c
  • Related