Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass lambdas with capturing to legacy callbacks

Tags:

c++

c++11

lambda

I'm using a C library in a C++11 project and this C library provides a function which expects a function pointer. I want to pass a C++11 lambda to it which works correctly unless I capture variables. Here is a short example:

#include <cstdio>
#include <functional>

typedef int (*Callback)();

void legacy(Callback callback) {
    printf("%i\n", callback());
}

int stdCallback() {    
    return 1; 
}

int main(int argc, char* argv[]) {
    int number = 3;    

    // Standard C callback works
    legacy(stdCallback);

    // Lambda without capturing works
    legacy([]() { return 2; });    

    // Lambda with capturing doesn't work
    legacy([&]() { return number; });

    return 0;
}

The GNU C++ compiler gives me the following error message in the third call to the legacy function:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:24:36: error: cannot convert ‘main(int, char**)::<lambda()>’ to ‘Callback {aka int (*)()}’ for argument ‘1’ to ‘void legacy(Callback)’
 legacy([&]() { return number; });

How can I fix this? Or is it technically not possible to use a capturing lambda as a C function pointer?

like image 853
kayahr Avatar asked Feb 10 '15 10:02

kayahr


1 Answers

No, you can't convert a lamdba to a function pointer if it captures anything.

C++ Standard, section § 5.1.2 / 6 : [expr.prim.lambda], emphasis mine :

The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C ++ language linkage (7.5) 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

like image 160
quantdev Avatar answered Oct 02 '22 00:10

quantdev