2016-11-10 1 views
2

J'ai créé un modèle de classe avec un élément const statique. L'intention est que chaque spécialisation du modèle ait sa propre version/valeur de cet élément statique. Voici mon exemple de code:Initialisation d'un const statique pour une spécialisation de modèle

template < typename T > class C 
{ 
    public: 
     static const std::string NAME; 
     T something; 
     void printName() { std::cout << NAME << std::endl; } 
}; 

class C1 : public C<int>{}; 
class C2 : public C<char>{}; 

template<> const std::string C<int>::NAME{ "my int" }; // compiles 
template<> const std::string C<char>::NAME{ "my char" }; // compiles 

//template<> const std::string C1::NAME{ "my int" }; // doesn't compile 
//template<> const std::string C2::NAME{ "my char" }; // doesn't compile 

//const std::string C1::NAME{ "my int" }; // doesn't compile 
//const std::string C2::NAME{ "my char" }; // doesn't compile 

int main() 
{ 
    C1 c1; 
    C2 c2; 

    c1.printName(); 
    c2.printName(); 

    std::cout << c1.NAME << " " << c2.NAME << std::endl; 
    std::cout << C1::NAME << " " << C2::NAME << std::endl; 
} 

Lorsque vous utilisez la version compilable, la sortie est ce que j'attendais:

my int 
my char 
my int my char 
my int my char 

Pour les lignes qui ne compilent pas, le message d'erreur (en utilisant gcc 4.4) dit

ISO C++ does not permit 'C<int>::NAME' to be defined as 'C1::NAME' 

Pourquoi est-ce interdit? Ma compréhension est qu'une spécialisation complète d'un template est une classe dans tous les aspects (?), Et cette classe a tous les membres déclarés dans le template. Je m'attendrais donc à pouvoir faire référence à des membres statiques de cette classe en utilisant un opérateur de résolution d'étendue. Apparemment, je peux le faire après l'initialisation, comme dans la dernière ligne de main ci-dessus, mais pas dans l'initialisation elle-même.

Quelqu'un peut-il donner un aperçu de la raison pour laquelle la norme a été écrite de cette façon? Quel genre de problèmes surgiraient si la norme permettait la «mauvaise» syntaxe ci-dessus?

Répondre

3

Il me semble que le problème que vous rencontrez n'a rien à voir avec les modèles. Le problème est que vous essayez de définir un membre statique à l'aide d'une classe dérivée dans le nested-name-specifier, pas la classe d'origine. Vous auriez le même problème ici:

struct A { 
    static int x; 
}; 
struct B : A{}; 
int B::x = 42; 

Le C1 et C2 dans votre code ne sont pas des spécialisations complètes de C, plutôt, ils sont issus des classes de spécialisations de C. Donc, je ne sais pas ce que vous attendez ici ...

+0

Cela rend les choses plus claires. Je suis nouveau dans les templates et j'essaye toujours de trier des concepts comme l'instanciation vs la spécialisation, et comment les combiner avec l'héritage, etc. Voyons voir si j'ai ceci correct maintenant: La façon dont j'ai déclaré la classe C1, le compilateur va générer un implicite) instanciation de C , qui sera la classe de base pour C1. Le membre statique appartient à la classe de base, j'ai donc besoin d'utiliser le nom de la classe de base "C " pour l'initialiser. De même pour C2 & C . C et C n'ont pas de relation d'héritage; ils sont simplement générés à partir du même modèle. Est-ce vrai? – user3065699

+0

Quant à ce que j'attends, je veux que C1 et C2 (ou peut-être plus précisément, leurs classes de base respectives) aient chacun un membre statique appelé NAME, avec des valeurs différentes pour chaque classe (de base). C'est ce que j'ai réussi à finir avec; Je n'étais pas très clair comment cela fonctionnait. – user3065699