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

后端 未结 3 1336
北海茫月
北海茫月 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: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.

提交回复
热议问题