¿Cómo reenviar declarar una clase de plantilla C ++?

101

Dada una clase de plantilla como la siguiente:

template<typename Type, typename IDType=typename Type::IDType>
class Mappings
{
public:
    ...
    Type valueFor(const IDType& id) { // return value }
    ...
};

¿Cómo puede alguien declarar adelante esta clase en un archivo de encabezado?

Tron Thomas
fuente

Respuestas:

104

Así es como lo harías:

template<typename Type, typename IDType=typename Type::IDType>
class Mappings;

template<typename Type, typename IDType>
class Mappings
{
public:
    ...
    Type valueFor(const IDType& id) { // return value }
    ...
};

Tenga en cuenta que el valor predeterminado está en la declaración de reenvío y no en la definición real.

Pubby
fuente
Es posible declarar hacia adelante una clase que tiene sus valores predeterminados enumerados en su definición. Mira mi respuesta.
Elliott
Estoy en desacuerdo. El estándar dice: "Un parámetro de plantilla no debe recibir argumentos predeterminados por dos declaraciones diferentes en el mismo ámbito" . Y no encontré nada sobre los valores predeterminados solo en la primera declaración. Además, el código con la declaración de reenvío y los valores predeterminados en la definición se compila y ejecuta correctamente. ¿Estás seguro de lo que reclamas? ¿Puede proporcionar una cotización de la norma?
Olek Stolar
@Elliott Parece que es verdad. El estándar [17.1.9] dice: "Se puede especificar un argumento de plantilla predeterminado en una declaración de plantilla". No debe ser, pero puede ser. Por lo tanto, no entiendo por qué otras respuestas afirman que debería estar en la primera declaración.
Olek Stolar
Y parece ser mucho más conveniente tener valores predeterminados en la definición.
Olek Stolar
8

Puede declarar argumentos predeterminados para una plantilla solo para la primera declaración de la plantilla. Si desea permitir que los usuarios reenvíen una plantilla de clase, debe proporcionar un encabezado de reenvío. Si desea reenviar la declaración de la plantilla de clase de otra persona utilizando valores predeterminados, ¡no tiene suerte!

Dietmar Kühl
fuente
Es posible declarar hacia adelante una clase que tiene sus valores predeterminados enumerados en su definición. Mira mi respuesta.
Elliott
Estoy en desacuerdo. El estándar dice: "Un parámetro de plantilla no debe recibir argumentos predeterminados por dos declaraciones diferentes en el mismo ámbito" . Y no encontré nada sobre los valores predeterminados solo en la primera declaración. Además, el código con la declaración de reenvío y los valores predeterminados en la definición se compila y ejecuta correctamente. ¿Estás seguro de lo que reclamas? ¿Puede proporcionar una cotización de la norma?
Olek Stolar
3

Usted puede declarar una clase de plantilla cuya definición establece los argumentos por defecto, pero cada vez se hace referencia a la clase debe incluir todos sus argumentos hasta que se introduce la definición.

p.ej. Usemos std::vectorsin incluirlo (el segundo argumento de std::vectorestá definido con un valor predeterminado):

namespace std
{
    template<typename, typename>
    class vector;
}

#include <iostream>

template <typename S, typename T>
void Foo (const std::vector<S,T> & vector)
{
    std::cout << "do vector stuff, eg., display size = "
        << vector.size() << std::endl;
}

template <typename T>
void Foo (const T & t)
{
    std::cout << "do non-vector stuff..." << std::endl;
}

Luego podemos usarlo sin incluir el vector, por ejemplo:

int main()
{
    Foo(3);
}

Y podemos usarlo con std::vector , por ejemplo:

#include <vector>

// Now the compiler understands how to handle
// std::vector with one argument
// (making use of its default argument)

int main()
{
    Foo(std::vector<int>(3));
}

No he comprobado los estándares, pero esto funciona en clang/ gcccon -std=c++98hasta -std=c++17, por lo que si no es oficialmente un estándar, parece que no lo es oficialmente.

Elliott
fuente
Tal vez te olvides de los corchetes vacíos Foo<> foo;.
Olek Stolar
@ OleksijPlotnyc'kyj tienes razón. Gracias. Eliminé esa adición.
Elliott