2011-07-18 14 views
6

Al responder la pregunta this, me encontré con esta diferencia de comportamiento con respecto a la creación de instancias de plantillas.¿Cuáles son las reglas en torno a la instanciación de tipos de plantilla (clase/función) cuando se toma una dirección?

Inicialmente hay una plantilla de función

template <typename T> void my_callback(void* data) { … } 

Ahora algo requiere la dirección de este - en concreto un void*, por lo que el enfoque obvio es

bar(reinterpret_cast<void*>(&my_callback<int>)); 

Sin embargo, con las versiones del compilador pre gcc 4.5, esto falla con un contexto no suficiente ... error. Bien - por lo que la solución es "fundido" en primer lugar - lo que obliga a instancias, es decir:

void (*callback)(void*) = my_callback<int>; 
bar(reinterpret_cast<void*>(callback)); 

Esto funciona bien.

Ahora el segundo escenario, en lugar de ser una función gratuita, es un miembro estático de una plantilla de clase, es decir

template <typename T> 
struct foo 
{ 
    static void my_callback(void* data) { 
    T& x = *static_cast<T*>(data); 
    std:: cout << "Call[T] with " << x << std::endl; 
    } 
}; 

Ahora, el original reinterpret_cast funciona bien.

bar(reinterpret_cast<void*>(&foo<int>::my_callback)); 

Así que mi pregunta es: ¿por qué esta aparente diferencia en el comportamiento?

+0

lol ... tomando prestado de una pregunta bastante reciente que veo :) +1, la pregunta es realmente interesante. –

Respuesta

2

De n3290, 14.7.1 instanciación implícito [temp.inst]

2 A menos que una especialización de plantilla de función ha sido explícitamente instancia especializada o explícitamente, la especialización de plantilla de función se crea una instancia implícitamente cuando la especialización es referenciado en un contexto que requiere la existencia de una definición de función.

Existen reglas similares en el párrafo 1 para las especializaciones de plantilla de clase. Tenga en cuenta que el estándar habla en términos de especialización porque una especialización se declara implícitamente cuando se utiliza una plantilla y no existe una especialización proporcionada por el usuario, al menos para plantillas de funciones (párrafo 8).

En combinación con el párrafo 10,

10 Una implementación no será una instancia de forma implícita una plantilla de función , una plantilla de miembro, una función miembro no virtual, una clase miembro de , o un miembro de datos estático de una la plantilla de clase que no requiere requiere instanciación.

creo que la regla de oro es: tan pronto como se necesita un miembro/función de objeto/clase o para hacer que el programa funcione de otra manera (hablando de manera informal), la plantilla se crea una instancia implícita pero no antes . Esto incluye tomar la dirección de una función.

cuanto a la cuestión se ha vinculado, algunos usos de reinterpret_cast puede hacer que el programa no conforme, momento en el cual es irrelevante mencionar ejemplificaciones - I invite you to see my answer there < /descarada>.

+0

así que básicamente, para tomar la dirección de un miembro (incluso estático), el tipo tiene que ser instanciado, por lo que el compilador lo hará, pero no para una función gratuita porque no necesita ... thx. – Nim

+1

@Nim: La obtención de la dirección de una función requiere la definición de la función (a partir de la cual el vinculador obtendrá la dirección), por lo que obtener la dirección de una función de plantilla implica la instanciación de esa especialización particular de la función. –

+0

@David, sí, por lo que pregunté, ¿cómo es que la reinterpretación_cast de la dirección de no funciona para una plantilla de función, tbh, todavía no he probado la versión indirecta como en la respuesta de Luc? – Nim

Cuestiones relacionadas