2010-05-29 18 views
15

Ayer estaba pensando si sería posible usar la conveniencia de las funciones lambda C++ 0x para escribir devoluciones de llamada para las funciones API de Windows.¿C++ soportará 0x __stdcall o extern captura "C" -nada lambdas?

Por ejemplo, ¿qué ocurre si quiero utilizar una lambda como EnumChildProc con EnumChildWindows? Algo así como:

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

Otro uso sería escribir extern "C" devoluciones de llamada para rutinas C. P. ej .:

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; 
    })); 

¿Esto es posible?

Entiendo que las lambdas que capturan variables nunca serán compatibles con C, pero al menos me parece posible que capture-nothing lambdas puedan ser compatibles.

+0

Esto se aclaró en un informe de defectos contra el estándar C++ 11, como explico en mi respuesta a continuación. –

Respuesta

14

Lambdas sin una captura are implicitly convertible a un puntero a la función (por una función de conversión no explícita definida por el tipo de cierre).

El FCD no parece especificar qué enlace de idiomas tiene el tipo de función de ese tipo de puntero a función, por lo que si necesita pasar este puntero a funciones C, la convención de llamadas de las funciones C++ y C necesita ser mismo. Creo que en Windows, sin embargo, ese es el caso. Por lo que debe ser capaz de pasar la lambda a funciones API de Windows

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

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

FCD redacción en 5.1.2/6:

El tipo de cierre para un lambda-expresión sin lambda de captura tiene un público no virtual la función de conversión no explícita const al puntero a la función que tiene el mismo parámetro y los mismos tipos de retorno que el operador de llamada de función del tipo de cierre. El valor devuelto por esta función de conversión será la dirección de una función que, cuando se invoca, tiene el mismo efecto que invocar el operador de llamada de función del tipo de cierre.

creo que el final de norma debe tener una nota que dice que hay una función de conversión a ambos punteros de C función de enlace y C++ punteros de función de vinculación, como la convertibilidad de los punteros de función C es uno de los objetivos de esta funcionalidad.

2

No hay una razón particularmente buena para que esto no se extienda a la captura de lambdas. Requiere un poco de generación de código dinámico, pero no debería estar más allá del ingenio de los escritores de compilación, y haría más fácil la interoperabilidad con las antiguas API C de gran magnitud: ya no es necesario pasar los parámetros a través de los vacíos sin tipo (que no todos APIs incluso ofrecen).

+1

El problema no es la generación de código dinámico, sino la limpieza dinámica del código. Tendría que tener un GC de nivel de idioma para limpiar ese código. – Puppy

+2

No más que cualquier otra cosa en C++. Un shared_ptr a un thunk sería suficiente. – DrPizza

1

El enlace del lenguaje de los resultados de un puntero de función de conversión de un lambda-captura menos no se ha especificado en el estándar de C++ 11, pero fue tratado en defect report 1557 que dice:

5.1.2 [expr .prim.lambda] El párrafo 6 no especifica el enlace de idioma del tipo de función de la función de conversión del tipo de cierre.

y la resolución fue que el enlace del lenguaje debe ser C++:

El tipo de cierre para un lambda-expresión sin lambda de captura tiene una función de conversión const no virtual no explícita público a puntero para funcionar con enlace de lenguaje C++ (7.5 [dcl.link]). teniendo los mismos tipos de parámetro y retorno que el operador de llamada de función del tipo de cierre. El valor devuelto ...

podemos encontrar este lenguaje en la norma 14 del proyecto de C++, ya que el estado es DRWP parece que esto no se aplica a C++ 11.

+0

Gran hallazgo. Pero si fue un Defecto elevado y aceptado durante la vida de C++ 11, seguramente eso significa que definitivamente ** se aplica ** a C++ 11? –

+0

@underscore_d si miramos la [lista actual de problemas activos] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html) que define los términos tales como 'DRWP' dice : 'Un problema de DR cuya resolución se refleja en el documento de trabajo actual. El documento de trabajo es un borrador de una versión futura de la Norma. "Que, por lo que puedo decir, significa que se aplica a C++ 14 y no a C++ 11. –