2012-03-09 18 views

Respuesta

15

En C++ 03, la especificación prohíbe explícitamente el argumento predeterminado de ser utilizado para deducir un argumento de plantilla (C++ 03 §14.8.2/17):

A template type-parameter cannot be deduced from the type of a function default argument.

En C++ 11 , puede proporcionar un argumento de plantilla predeterminado para la plantilla de función:

template <typename T = float> 
void bar(int a, T b = 0.0f) { } 

No obstante, se requiere el argumento de plantilla predeterminado. Si no se proporciona el argumento de la plantilla por defecto, el argumento de la función predeterminada aún no se puede utilizar para la deducción del argumento de la plantilla. Específicamente, se aplica lo siguiente (C++ 11 14.8.2.5/5):

The non-deduced contexts are:

...

  • A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
+10

Si bien decir "Porque el estándar lo dice" es una respuesta válida, sería bueno saber el razonamiento detrás de esto. –

+1

Entre otras razones, diferentes declaraciones de una función pueden declarar diferentes argumentos predeterminados (estoy bastante seguro de que lo mismo se aplica a las plantillas de función). –

+1

@Juegos: No, las declaraciones diferentes no pueden declarar diferentes argumentos predeterminados. Ni siquiera está permitido que múltiples declaraciones den el mismo valor predeterminado al mismo argumento. 8.3.6 dice "Un argumento predeterminado no será redefinido por una declaración posterior (ni siquiera al mismo valor)". Por supuesto, eso solo se aplica a las funciones que no son de plantilla. Para funciones de plantilla, parece que los argumentos predeterminados solo se pueden proporcionar en la declaración inicial. –

4

Una buena razón podría ser que

void foo(bar, xyzzy = 0); 

es similar a un par de sobrecargas.

void foo(bar b) { foo(b, 0); } 
foo(bar, xyzzy); 

Por otra parte, a veces es ventajoso refactorizar en tales:

void foo(bar b) { /* something other than foo(b, 0); */ } 
foo(bar, xyzzy); 

Incluso cuando se escribe como una sola, es todavía como dos funciones en uno, ninguno de los cuales es "preferido" en ningún sentido . Llamas a la función de un argumento; el de dos argumentos es efectivamente una función diferente. La notación de argumento predeterminada simplemente los fusiona en uno.

Si la sobrecarga tuviera el comportamiento que está solicitando, para coherencia tendría que funcionar en el caso cuando la plantilla se divide en dos definiciones. ¡Eso no tendría sentido porque entonces la deducción sería extraer tipos de una función no relacionada que no se está llamando! Y si no se implementara, significaría que la sobrecarga de diferentes longitudes de listas de parámetros se convierte en un "ciudadano de segunda clase" en comparación con "argumentos predeterminados".

Es bueno si la diferencia entre sobrecargas y valores predeterminados está completamente oculta para el cliente.

7

Habría algunas dificultades técnicas para lograr eso en general. Recuerde que los argumentos predeterminados en las plantillas no se crean instancias hasta que sean necesarios. Consideremos a continuación:

template<typename T, typename U> void f(U p = T::g()); // (A) 
template<typename T> T f(long, int = T()); // (B) 
int r = f<int>(1); 

Esto se resuelve mediante la realización de hoy (entre otras cosas) los siguientes pasos:

  1. intento de deducir los parámetros de plantilla para los candidatos (A) y (B); esto falla para (A), que por lo tanto se elimina.
  2. realiza la resolución de sobrecarga; (B) se selecciona de entre
  3. la llamada, una instancia del argumento predeterminado

Para deducir a partir de un argumento por defecto, que el argumento por defecto tendría que ser en sí una instancia antes de completar el proceso de deducción. Eso podría fallar, lo que llevaría a errores fuera del contexto de SFINAE. Es decir, un candidato que puede ser totalmente inapropiado para una llamada podría desencadenar un error.

+0

Me parece razonable. –

Cuestiones relacionadas