Comment transférer déclarer une classe de modèle C ++?

101

Étant donné une classe de modèle comme celle-ci:

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

Comment quelqu'un peut-il déclarer cette classe dans un fichier d'en-tête?

Tron Thomas
la source

Réponses:

104

Voici comment vous feriez:

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 }
    ...
};

Notez que la valeur par défaut est dans la déclaration avant et non dans la définition réelle.

Pubby
la source
Il est possible de déclarer en avant une classe dont les valeurs par défaut sont répertoriées dans sa définition. Voyez ma réponse.
Elliott
Je ne suis pas d'accord. La norme dit: "Un paramètre de modèle ne doit pas recevoir d'arguments par défaut par deux déclarations différentes dans la même portée" . Et je n'ai rien trouvé sur les défauts dans la première déclaration uniquement. De plus, le code avec la déclaration avant et les valeurs par défaut dans la définition se compile et s'exécute avec succès. Etes-vous sûr de ce que vous réclamez? Pouvez-vous fournir un devis de la norme?
olek stolar
@Elliott Il semble que c'est vrai. La norme [17.1.9] dit: "Un argument modèle par défaut peut être spécifié dans une déclaration de modèle." Non doit être, mais peut-être. Je ne comprends donc pas pourquoi d'autres réponses prétendent que cela devrait figurer dans la première déclaration.
olek stolar
Et il semble être beaucoup plus pratique d'avoir des valeurs par défaut dans la définition.
olek stolar
8

Vous pouvez déclarer des arguments par défaut pour un modèle uniquement pour la première déclaration du modèle. Si vous souhaitez autoriser les utilisateurs à transmettre la déclaration d'un modèle de classe, vous devez fournir un en-tête de transfert. Si vous souhaitez transférer déclarer le modèle de classe de quelqu'un d'autre en utilisant les valeurs par défaut, vous n'avez pas de chance!

Dietmar Kühl
la source
Il est possible de déclarer en avant une classe dont les valeurs par défaut sont répertoriées dans sa définition. Voyez ma réponse.
Elliott
Je ne suis pas d'accord. La norme dit: "Un paramètre de modèle ne doit pas recevoir d'arguments par défaut par deux déclarations différentes dans la même portée" . Et je n'ai rien trouvé sur les défauts dans la première déclaration uniquement. De plus, le code avec la déclaration avant et les valeurs par défaut dans la définition se compile et s'exécute avec succès. Etes-vous sûr de ce que vous réclamez? Pouvez-vous fournir un devis de la norme?
olek stolar
3

Vous pouvez déclarer une classe basée sur un modèle dont la définition indique les arguments par défaut, mais chaque fois que vous référencez la classe, vous devez inclure tous ses arguments jusqu'à ce que la définition soit introduite.

par exemple. Utilisons std::vectorsans l'inclure (le deuxième argument de std::vectorest défini avec une valeur par défaut):

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;
}

On peut alors l'utiliser sans inclure le vecteur, par exemple:

int main()
{
    Foo(3);
}

Et nous pouvons l'utiliser avec std::vector , par exemple:

#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));
}

Je n'ai pas vérifié les normes, mais cela fonctionne sur clang/ gccavec -std=c++98jusqu'à -std=c++17, donc si ce n'est pas officiellement une norme, cela semble être officieusement le cas.

Elliott
la source
Peut-être que vous oubliez les crochets vides Foo<> foo;.
olek stolar
@ OleksijPlotnyc'kyj vous avez raison. Merci. J'ai supprimé cet ajout.
Elliott