2011-03-11 8 views
5

estoy tratando de tener un puntero a una instancia de plantilla de función y echarlo a void *:¿Transmitir directamente desde el puntero a una función de plantilla?

#include <stdio.h> 

void plainFunction(int *param) {} 

template <typename T> 
void templateFunction(T *param) {} 

int main() { 
    void *addr1=&plainFunction; //OK 
    void *addr2=&templateFunction<int>; //Compile error 
} 

me sale el siguiente error (en Visual Studio 2008)

main.cu(10) : error C2440: 'initializing' : cannot convert from 'void (__cdecl *)(T *)' to 'void *' 
Context does not allow for disambiguation of overloaded function 

¿Por qué es ¿sucediendo? La función templateFunction (para concreto tipo T=int) no está sobrecargada. Es posible deducir a qué instancia de la función me refiero.

Si se sustituye la línea de erroneus con:

void (*foo)(int*)=&templateFunction<int>; 
void *addr2=foo; 

Se compila sin ningún problema.

¡Gracias!


Actualización:

Cuando puntero normal de void* se sustituye por puntero de función ficticia void(*)(), según lo sugerido por James (gracias), que hace que el error desaparezca:

void (*addr1)()=(void(*)())&plainFunction; 
void (*addr2)()=(void(*)())(&templateFunction<int>); 

Sin embargo, si el error fue causado al convertir una función-puntero a un puntero normal, el compilador debería presentar una queja en ambos casos. Sin embargo, no lo hace, así que continúo asumiendo que es correcto al menos para este compilador. Si no me equivoco, el estándar simplemente dice que los punteros a las funciones no se representan como a como los punteros normales, pero no lo prohíbe.

+0

cuanto a su actualización, no importa si los punteros a funciones y referencias a objetos tienen el mismo tamaño y representación: la conversión de un puntero de función a '' void * simplemente no está permitido.Tenga en cuenta que con su actualización, no puede llamar a ninguna de las funciones a través de 'void (*)()' porque ese no es el tipo de función; Tendría que convertir 'addr1' o' addr2' de nuevo en el tipo correcto ('void (*) (int *)') para realizar la llamada; de lo contrario, el comportamiento no está definido. –

+0

Lo que realmente necesito es un "punto de entrada de función" que luego se pasa a la biblioteca CUDA. La función, en realidad tomo puntero para que nunca exista como pieza de código ejecutable por CPU, reside en la GPU. Acabo de despojarme de material específico de CUDA para que mi ejemplo sea lo más simple posible y obtener información de personas que trabajan con C++ pero no necesariamente con CUDA. Y no me equivoqué al hacerlo, tu respuesta me abrió los ojos sobre el aspecto de los indicadores de función que no conocía, a pesar de que ya los usaba muchas veces. Gracias. – CygnusX1

Respuesta

12

Ambos son técnicamente incorrectos: en C++, no se puede convertir un puntero a un void*.

Los tipos de puntero a función (como void (*)(int*) aquí) son una clase completamente diferente de tipos que tipos de puntero a objeto (como void* aquí).

Visual C++ que permite la conversión en absoluto (por ejemplo, en void* addr1 = &plainFunction;) es una extensión del lenguaje (compilar con la bandera /Za, que desactiva extensiones de lenguaje, hace que ambas líneas a ser rechazados).

El error es un poco engañoso, sin duda, aunque algunos otros compiladores son igualmente inútiles (Comeau informa "error: ninguna instancia de plantilla de función" templateFunction "coincide con el tipo requerido").

+0

Tiene razón, aunque normalmente los punteros a las funciones _se_ pueden enviar a la función normal. Corregir la pregunta para que coincida con el estándar. – CygnusX1

+0

@ CygnusX1: No estoy seguro de entender tu comentario. Como ha demostrado, Visual C++ _does_ le permite asignar la dirección de una instancia de plantilla de función a un puntero de función. –

+0

Porque quise decir "tienes razón, aunque por lo general los punteros a las funciones se pueden convertir a los ** indicadores **". Mi culpa. Lo siento. Pienso una cosa y escribo otra. – CygnusX1

6

El compilador debe generar un error en ambos casos. Los punteros de función no son convertibles a void * de acuerdo con la Norma § 4.10/2 ya que las funciones no son objetos (§ 1.8/1). Visual Studio 2008 permite esto como una extensión, marque this bug.

Uso typedef para evitar malentendidos:

typedef void(func)(int*); // declare func type 
func* addr1 = &plainFunction;   // OK 
func* addr2 = &templateFunction<int>; // OK 
+0

Bueno, VS2008 no genera el error en este último caso. – CygnusX1

+0

Oh. ¿Así que dices, convertir a 'void *' es _un_contra el estándar y no es simplemente "no tiene que, pero puede"? – CygnusX1

+1

"no son convertibles" significa que la Norma prohíbe eso. VS2008 no es un compilador conforme estándar. No debe usar ese error en VS2008 si desea mantener su código portátil. –

Cuestiones relacionadas