2011-08-18 14 views
8

Lo siento si esto se ha preguntado antes, pero no he podido encontrarlo.¿pasar función por valor (?) En lugar de puntero a la función?

Así que estoy tratando de educarme sobre las plantillas y las nuevas características de C++ 11 (principalmente lambdas, algo que siempre me ha gustado en otros idiomas).

Pero en mis pruebas me vinieron a algo que no tenía idea funcionó, y yo estoy tratando de entender cómo funciona figura, pero no puede salir ..

El siguiente código:

template <class Func> 
void Test(Func callback) { 
    callback(3); 
} 

void Callback(int i) { 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) { 
    Test(&Callback); // this I was expecting to work, compiler will see its a pointer to a function 
    Test(Callback); // this also works, but how?! 
    return 0; 
} 

Si entiendo cómo funcionan las plantillas, básicamente son un esquema para que el compilador sepa qué construir, así que la primera llamada Test(&Callback); esperaba trabajar porque el compilador verá que la plantilla recibe una dirección de función y asumirá que los argumentos deberían ser un puntero.

Pero, ¿cuál es la segunda llamada? ¿Cuál es la plantilla suponiendo que sea? Una copia de una función (si eso tiene sentido)

Respuesta

14

Una función es implícitamente convertible a un puntero a sí mismo; esta conversión ocurre en casi todas partes. Test(Callback) es exactamente lo mismo que Test(&Callback). No hay diferencia. En ambos casos, Func se deduce que es void(*)(int).

Los punteros de función son raros. Puede encontrar más información sobre ellos en "Why do all these crazy function pointer definitions all work?"

+0

gracias por la respuesta. así que si no usé plantillas y declare Test like: void Test (void (* callback) (int)) {...} ambas llamadas también funcionarían. Es bueno saberlo. Me aseguro de leer el hilo que vinculó. – sap

3

En C++, las funciones no son objetos de primera clase, lo que significa que "la función como valor" no tiene sentido. Es por eso que el nombre de la función siempre ha sido implícitamente convertible en puntero a él.

+0

Quizás vale la pena señalar que hay idiomas en los que "función por valor" tiene sentido. – hamstergene

2

Las funciones son implícitamente convertibles en punteros a funciones. De hecho, no hay forma de obtener un valor de función o referencia. Aunque, curiosamente, puedes crear un tipo de valor de función, simplemente no puedes asignarle nada.

Here is code snippit que demuestra cómo las lambdas y varias devoluciones de llamada reaccionan con las plantillas.

+0

gracias por el código, realmente útil. – sap

+0

Esto está mal. Las referencias de funciones están bien. Si 'Test' se declaró como' prueba vacía (Func & callback) ', entonces' Func' se deduciría a 'void (int)', y 'Callback' se pasaría por referencia, sin convertirlo a un puntero, a' Prueba'. –

+0

¡Guau! Supongo que tiene sentido que la referencia sea compatible, así como los punteros, ya que son muy similares. ¿Es posible declarar un valor de función y asignarle algo? –

0

En C++ 11 (y boost y tr1) tenemos std :: function como tipo de plantilla para almacenar functors, lambdas y funciones. Entonces definitivamente puede tener el concepto de mantener un valor de función en una variable de tipo std :: function. esa variable también puede estar "vacía", lo que significa que no se almacena ninguna función (referencia) en ella. Entonces no puede ser llamado.

La pregunta original se refiere a que, a diferencia de C, C++ permite referencias a funciones. Además, por razones de compatibilidad con C, un nombre de función puede degenerar a un puntero de función. Pero debido a la sobrecarga, las cosas son más "interesantes" en C++ que en C.

Cuestiones relacionadas