Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will C++0x support __stdcall or extern "C" capture-nothing lambdas?

Tags:

c++

c

c++11

lambda

Yesterday I was thinking about whether it would be possible to use the convenience of C++0x lambda functions to write callbacks for Windows API functions.

For example, what if I wanted to use a lambda as an EnumChildProc with EnumChildWindows? Something like:

EnumChildWindows(hTrayWnd, CALLBACK [](HWND hWnd, LPARAM lParam) {
        // ...
        return static_cast<BOOL>(TRUE); // continue enumerating
    }, reinterpret_cast<LPARAM>(&myData));

Another use would be to write extern "C" callbacks for C routines. E.g.:

my_class *pRes = static_cast<my_class*>(bsearch(&key, myClassObjectsArr, myClassObjectsArr_size, sizeof(my_class), extern "C" [](const void *pV1, const void *pV2) {
        const my_class& o1 = *static_cast<const my_class*>(pV1);
        const my_class& o2 = *static_cast<const my_class*>(pV2);

        int res;
        // ...
        return res;
    }));

Is this possible?

I can understand that lambdas that capture variables will never be compatible with C, but it at least seems possible to me that capture-nothing lambdas can be compatible.

like image 542
Daniel Trebbien Avatar asked May 29 '10 13:05

Daniel Trebbien


3 Answers

Lambdas without a capture are implicitly convertible to a pointer to function (by a non-explicit conversion function defined by the closure type).

The FCD does not seem to specify what language linkage the function type of that function pointer type has, so if you need to pass this function pointer to C functions, the calling convention of C++ functions and C functions need to be the same. I believe that on Windows, that is the case though. So you should be able to pass the lambda to Windows API functions

typedef void(*callbackType)(void *userData);
extern "C" void someCFunction(callbackType callback);

int main() {
  someCFunction([](void *userData) { /* ... */ });
}

FCD wording at 5.1.2/6:

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.

I think the final Standard should have a note that says that there is a conversion function to both C linkage function pointers and C++ linkage function pointers, as convertibility to C function pointers is one of the goal of this functionality.

like image 128
Johannes Schaub - litb Avatar answered Oct 18 '22 17:10

Johannes Schaub - litb


The language linkage of the function pointer results from a conversion of a capture-less lambda was not specified in the C++11 standard but was addressed in defect report 1557 which says:

5.1.2 [expr.prim.lambda] paragraph 6 does not specify the language linkage of the function type of the closure type's conversion function.

and the resolution was that the language linkage should be C++:

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 with C++ language linkage (7.5 [dcl.link]). having the same parameter and return types as the closure type's function call operator. The value returned...

we can find this language in the draft C++14 standard, since the status is DRWP it seems like this does not apply to C++11.

like image 44
Shafik Yaghmour Avatar answered Oct 18 '22 17:10

Shafik Yaghmour


There's no particularly good reason that this shouldn't be extended to capturing lambdas. It requires some dynamic code generation, but it shouldn't be beyond the wit of compiler writers, and it would make interop with old C APIs orders of magnitude easier--no more need to pass parameters through untyped void*s (which not all APIs even offer).

like image 37
DrPizza Avatar answered Oct 18 '22 16:10

DrPizza