Is it safe to cast a lambda function to a function pointer?

后端 未结 3 1244
北海茫月
北海茫月 2020-12-16 15:33

I have this code:

void foo(void (*bar)()) {
    bar();
}

int main() {
    foo([] {
        int x = 2;
    });
}

However, I\'m worried that

相关标签:
3条回答
  • 2020-12-16 16:06

    In addition to Nicol's perfectly correct general answer, I would add some views on your particular fears:

    However, I'm worried that this will suffer the same fate as ..., which takes the address of a local variable.

    Of course it does, but this is absolutely no problem when you just call it inside foo (in the same way your struct example is perfectly working), since the surrounding function (main in this case) that defined the local variable/lambda will outlive the called function (foo) anyway. It could only ever be a problem if you would safe that local variable or lambda pointer for later use. So

    Is the first example completely safe?

    Yes, it is, as is the second example, too.

    0 讨论(0)
  • 2020-12-16 16:10

    A lambda that captures nothing is implicitly convertible to a function pointer with its same argument list and return type. Only capture-less lambdas can do this; if it captures anything, then they can't.

    Unless you're using VS2010, which didn't implement that part of the standard, since it didn't exist yet when they were writing their compiler.

    0 讨论(0)
  • 2020-12-16 16:18

    Yes I believe the first example is safe, regardless of the life-time of all the temporaries created during the evaluation of the full-expression that involves the capture-less lambda-expression.

    Per the working draft (n3485) 5.1.2 [expr.prim.lambda] p6

    The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

    The above paragraph says nothing about the pointer-to-function's validity expiring after evaluation of the lambda-expression.

    For e.g., I would expect the following to work:

    auto L = []() {
       return [](int x, int y) { return x + y; };
    };
    
    int foo( int (*sum)(int, int) ) { return sum(3, 4); }
    
    
    int main() {
      foo( L() );
    }
    

    While implementation details of clang are certainly not the final word on C++ (the standard is), if it makes you feel any better, the way this is implemented in clang is that when the lambda expression is parsed and semantically analyzed a closure-type for the lambda expression is invented, and a static function is added to the class with semantics similar to the function call operator of the lambda. So even though the life-time of the lambda object returned by 'L()' is over within the body of 'foo', the conversion to pointer-to-function returns the address of a static function that is still valid.

    Consider the somewhat analagous case:

    struct B {
       static int f(int, int) { return 0; }
       typedef int (*fp_t)(int, int);
       operator fp_t() const { return &f; }
    };
    int main() {
      int (*fp)(int, int) = B{};
      fp(3, 4); // You would expect this to be ok.
    }
    

    I am certainly not a core-c++ expert, but FWIW, this is my interpretation of the letter of the standard, and I feel it is defendable.

    Hope this helps.

    0 讨论(0)
提交回复
热议问题