tags:

views:

158

answers:

3

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.

A: 

No. Lambdas are not and will never be C-compat. They're function objects that are created and managed by the compiler, and you can make them C compatible as much as

struct yay {
    void operator()();
};
DeadMG
I think a downvoter should explain the downvote for those of us who are unfamiliar with lambdas.
Nathan Adams
+10  A: 

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.

Johannes Schaub - litb
+2  A: 

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).

DrPizza