2011-03-28 8 views
5

mira el siguiente código de prueba:La elección entre instancias de plantilla con argumentos puntero

template<class T> struct Wrap {}; 

template<typename T> inline 
void fun (T *&Int)   // **choice 1** 
{} 

template<typename T> inline 
void fun (Wrap<T> *&Int) // **choice 2** 
{} 

int main() 
{ 
    int i = 6; 
    fun((char*&)(i));   // **call 1** 
    fun((Wrap<char>*&)(i)); // **call 2** 
} 

Cuando ejecuto este código en Linux g ++, que funciona de acuerdo con las expectativas. Cuando se llama a fun() con char * &, llama a la función de elección 1 directamente. Sin embargo, estoy interesado cuando llamamos a fun() con Wrap < char> * & y llama a la opción 2. Aunque las opciones 1 y 2 son válidas para la segunda llamada, el compilador elige una mejor contendiente -> choice 2 (porque existe).

Pregunta: ¿Se garantiza que, el mismo comportamiento se mantendrá para cualquier otro compilador para C++? Si no, ¿hay alguna otra alternativa para hacerlo determinista?

+0

el 'en línea' es casi inútil en las funciones de la plantilla. No es necesario porque son plantillas (no especializadas) por lo que no causará un error de enlazador y el compilador es mucho mejor que nosotros para determinar cuándo alinear y cuándo no ... y puede ignorar perfectamente su solicitud. –

Respuesta

2

Mientras que el código podría ser como una especialización de plantilla, que no es el caso. El lenguaje no permite especializaciones de función de plantilla parcial. Las dos son plantillas no relacionadas que resultan ser sobrecargas.

el compilador las operaciones de búsqueda hasta la llamada a fun((Wrap<char>*&) i) con los mecanismos de búsqueda habituales, se encuentran las dos plantillas y determinará que hay dos sobrecargas potenciales:

template <typename T> void fun(T*&);  // with T == Wrap<char> 
template <typename T> void fun(Wrap<T>*&) // with T == char 

resolución de sobrecarga determinará entonces que la segunda es una mejor coincidencia e instanciarlo. Esto está garantizado por el estándar, pero cuidado: no son la misma plantilla, sino plantillas diferentes y es posible que se encuentre con resultados no previstos. Mira el artículo @LiKao vinculado para obtener más información.

3

Alguien con un mejor conocimiento de la especificación puede confirmar esto, pero creo que como Wrap<T> es un tipo más específico que simplemente T, la llamada 2 siempre resolverá la 'opción 2' en todos los compiladores de plataformas.

+1

A menos que haya un error del compilador;) –

+0

Error del compilador? Nunca he oído hablar de uno ... :) –

6

La segunda opción se elige porque es más especializado que el de primera, es decir, T*& puede unirse a cualquier T* no temporal, pero Wrap<T>*& sólo puede unirse a una no temporal Wrap<T>*. Esto es estándar por lo que sé y debería ser un comportamiento portátil, pero lo que es y no es portátil en la práctica cuando se trata de este tipo de cosas a menudo no es la definición de lo que es estándar.

+3

De hecho, es portátil, pero no son especializaciones de una plantilla, sino dos plantillas separadas que resultan ser sobrecargas. –

1

Una cosa que puede hacer esto aún más problemático es que las reglas para especializar las clases de plantilla y las funciones de plantilla difieren mucho. Esto se aplica a la posibilidad de sobrecargar las funciones de la plantilla, mientras que no existe la posibilidad de sobrecargar las clases. Porque no soy tan firme sobre este tema me ponga el enlace a alguien que es capaz de explicarlo con mayor profundidad:

Herb Sutter: "Why Not Specialize Function Templates?"

+1

Esto no es una especialización aquí, sino una sobrecarga. Una especialización tendría una lista de parámetros de plantilla que aparece entre el identificador de función y los argumentos de función (así como una lista de parámetros de plantilla vacía que aparece después de la plantilla ya que las especializaciones de función son necesariamente especializaciones completas). –

Cuestiones relacionadas