Argumentos predeterminados de plantilla

151

Si se me permite hacer lo siguiente:

template <typename T = int>
class Foo{
};

¿Por qué no se me permite hacer lo siguiente en main?

Foo me;

Pero debo especificar lo siguiente:

Foo<int> me;

C ++ 11 introdujo argumentos de plantilla predeterminados y en este momento están siendo difíciles de entender.

usuario633658
fuente

Respuestas:

188

Tu tienes que hacer:

Foo<> me;

Los argumentos de la plantilla deben estar presentes, pero puede dejarlos vacíos.

Piense en ello como una función foocon un único argumento predeterminado. La expresión foono lo llamará, pero lo foo()hará. La sintaxis del argumento aún debe estar allí. Esto es consistente con eso.

Joseph Mansfield
fuente
44
@Pubby supongo que sería crear algunas complicaciones innecesarias si Foo podría ser un identificador de plantilla o podría ser una instanciación explícita en función de si hay un argumento predeterminado. Mejor mantener la sintaxis de instanciación explícita. Piense en ello como una función foocon un único parámetro predeterminado. No puedes llamarlo así foo, lo llamas con foo(). Tiene sentido mantener esto consistente.
Joseph Mansfield
2
@sftrabbit pero no puedes llamar a una función sin argumentos como fooninguno de los dos; FooSin embargo, puede nombrar una clase sin argumentos .
Seth Carnegie
44
@aschepler Con una función, los argumentos de la plantilla se pueden deducir de los argumentos de la función. Con una clase, no es posible decidir si se refería a una clase de plantilla con argumentos predeterminados o una clase que no es de plantilla.
Olaf Dietsche
21
@OlafDietsche pero no puede tener una clase de plantilla y una clase que no sea de plantilla con el mismo nombre, por lo que el compilador debería poder decidir simplemente mirando cuál es el nombre.
Seth Carnegie
77
@Pubby El comité estándar se preguntó lo mismo, supongo. Ahora, con C ++ 17, <>ya no es necesario en este caso. Mira mi respuesta para más detalles.
Paolo M
53

Con C ++ 17, puedes hacerlo.

Esta característica se denomina deducción de argumento de plantilla de clase y agrega más flexibilidad a la forma en que puede declarar variables de tipos con plantilla .

Entonces,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

ahora es código legal de C ++ .

Paolo M
fuente
55
Extraño. Simplemente lo probé en mi proyecto C ++ 17 y no funcionó: "el tipo de marcador de posición de plantilla 'const MyType' debe ir seguido de un simple ID de declarador". Estoy usando GCC 7.3.0.
Silicomancer
1
@Silicomancer Es difícil de decir sin ver su código y línea de comando ... ¿Tal vez está tratando con punteros como aquí ?
Paolo M
1
Clang no acepta lo que parece? coliru.stacked-crooked.com/a/c5d3c0f90ed263c2
Borgleader
1
@Borgleader Aparentemente, Coliru está usando clang 5.0. A juzgar por esto , debería admitir la deducción de argumentos de plantilla de C ++ 17, pero evidentemente el id no lo hace. Si prueba su mismo ejemplo en wandbox usando clang 7.0, funciona perfectamente.
Paolo M
2
@PaoloM Oh, genial, me alegra saber que es solo un problema de la versión del compilador. Gracias por mirar en esto.
Borgleader
19

No tienes permitido hacer eso, pero puedes hacerlo

typedef Foo<> Fooo;

y luego hacer

Fooo me;
g24l
fuente
¿Hay alguna diferencia en esto con un tipo predeterminado y: typedef Foo<float> Fooo;sin un tipo predeterminado?
qrikko
55
La forma en C ++ 11-ish sería decirusing Fooo = Foo<>;
Adrian W el
18

Puedes usar lo siguiente:

Foo<> me;

Y tenga que intser su argumento de plantilla. Los corchetes angulares son necesarios y no pueden omitirse.

Andy Prowl
fuente
Tiene sentido y gracias, pero, como se señala a continuación, ¿por qué el tipo especificado no debe estar presente?
user633658
@ user633658: ¿Quiso decir "especificador de tipo"? No estoy seguro de entenderlo
Andy Prowl
De todos modos, con respecto a la razón detrás de la necesidad de paréntesis angulares vacíos, solo puedo hacer conjeturas, y se trata de descartar posibles ambigüedades con el uso del nombre de la plantilla solo, pero tengo que confesar que no sé exactamente motivo
Andy Prowl
Sospecho firmemente que el requisito para <> es habilitar el analizador del compilador para determinar que se está refiriendo a una clase con plantilla llamada foo, en lugar de otra cosa llamada foo.
Mac