2010-10-29 14 views
20

El siguiente código no pudo pasar la compilación, ¿cuál es la consideración para este error de compilación?¿Por qué el argumento predeterminado no se puede especificar para una especialización de plantilla explícita?

template<class T> void f(T t) {}; 

template<> void f<char>(char c = 'a') {} 

mensaje de error: Los argumentos por defecto no están permitidos en una especialización explícita de una plantilla de función

+0

Comentario menor: no necesita un punto y coma después de la definición de la función. – vitaut

+1

No respondiendo realmente a la pregunta, pero ¿no sería más limpio/más fácil de usar la sobrecarga en lugar de la especialización? Para una discusión sobre sobrecarga versus especialización, vea estos artículos de Herb Sutter: [Artículo de revista de usuarios C/C++] (http://www.gotw.ca/publications/mill17.htm) y [GotW # 49] (http://www.gotw.ca/gotw/049.htm). –

+0

+1 a @Luc. Si solo haces 'void f (char c = 'a') {}' compila perfectamente bien. –

Respuesta

21

creo que la razón de este error se debe al hecho de que los argumentos por defecto en la plantilla de función aplican a su especialización también y no se le permite definir el argumento predeterminado más de una vez en C++.

considerar lo siguiente:

#include <iostream> 

template<class T> void f(T t = 'a') {} 

template<> void f<char>(char c) 
{ 
    std::cout << c << std::endl; 
} 

int main(int argc, char **argv) 
{ 
    f<char>(); 
} 

Esto imprimirá a lo que significa que la especialización se llama con el argumento por defecto definido en la plantilla principal.

Si necesita un argumento predeterminado diferente para cada especialidad se puede utilizar el enfoque se ilustra a continuación:

argumentos de la función por defecto
#include <iostream> 

template<class T> 
struct default_arg 
{ 
    static T get() { return T(); } 
}; 

template<class T> void f(T t = default_arg<T>::get()) {} 

template<> 
struct default_arg<char> 
{ 
    static char get() { return 'a'; } 
}; 

template<> void f<char>(char c) 
{ 
    std::cout << c << std::endl; 
} 

int main(int argc, char **argv) 
{ 
    f<char>(); 
} 
+0

Esto no es muy agradable .. Esto dice, que todos los tipos 'T' deben poder inicializarse con char .. O tener un operador de conversión apropiado para char. –

+0

@Kiril Kirov: Esto es solo un ejemplo para ilustrar el punto (por qué el compilador da este error). – vitaut

+0

Sí, pero igual ... De todos modos: +1 - por la idea, agregada después de la edición (: –

14

C++ 98 §12.7/21" no se especificarán en el ... especialización explícita de una plantilla de función ".

En cuanto a la lógica, creo que tiene que ver con que una llamada siempre se resuelve con la plantilla principal. Una llamada que deja fuera un argumento requerido por la plantilla principal, no se pudo resolver sin cambiar las reglas de búsqueda.

+0

+1 por citar la parte relevante del estándar. Nunca fue bueno en eso =) – vitaut

+1

De hecho, no se encuentran especializaciones explícitas por nombre-búsqueda. La deducción del argumento de la plantilla se realiza en la plantilla de la función, y si solo se llama por 'f()', no puede deducir 'T'. ¿Cómo se supone que debe elegir 'char'.Uno podría argumentar que se podría hacer 'f ()' y si existe una especialización explícita para 'f ' que proporcione un argumento predeterminado, se usaría. Pero veo poco uso para eso y solo complicaría aún más la deducción del argumento de la plantilla. –

2

La selección de la instancia de plantilla particular que se utilizará se basa en el tipo de parámetro proporcionado. Por lo tanto, la selección de la especialización explícita se realiza mediante el aprovisionamiento de un argumento char; solo en ese punto entra en juego el argumento predeterminado (como ha codificado) (donde es redundante).

Tiene sentido proporcionar argumentos predeterminados en la propia declaración de la plantilla. La desventaja es que usted debe especificar la especialización apropiada usted mismo (lo que elimina algunas de las ventajas de usar un argumento predeterminado en primer lugar).

Para lograr el comportamiento que (creo) desea, utilice lo siguiente.

template<class T> void f(T t) {} 

template<> void f<char>(char c) {} 

void f() { f('a'); } 
Cuestiones relacionadas