2012-06-12 7 views
3

Ceci est une question simple, et je suis sûr qu'il a déjà été répondu mais je n'arrive pas à trouver une bonne réponse.Exemple simple avec des modèles

J'ai une classe, Point

template<class T> 
Point{ 
\\code 
} 

... et maintenant je veux un vecteur de points, dont certains ont T sous forme d'entier qui ont T en double. Je veux écrire quelque chose comme

template<class T> 
std::vector<Point<T> > points; 

Mais, hélas, cela ne compile pas avec l'erreur « attendu expression primaire avant« modèle ». Je n'ai pas été capable de jouer avec ce code pour le faire fonctionner. Il est également important que les points soient dans la classe principale, donc je ne peux pas coller la déclaration de modèle en dehors de la fonction.

Si quelqu'un pouvait me diriger vers une solution, je serais très obligé.

Merci.

+2

Un vecteur ne peut contenir que des éléments d'un type. Vous pouvez donc choisir le point ou le point mais vous ne pouvez pas les mélanger. –

+0

Cela ne devrait-il pas être simplement 'std :: vector > points'? – knittl

+0

Voulez-vous un 'typedef' modélisé? – ereOn

Répondre

5

Si votre objectif est d'avoir un vector qui contient à la fois Point<int> et Point<double>, vous pouvez utiliser Boost Variant.

typedef boost::variant<Point<int>, Point<double> > VariantPoint; 

Puis:

std::vector<VariantPoint> my_vector; 

my_vector.push_back(Point<int>(1, 0)); 
my_vector.push_back(Point<double>(1.5f, 2.0f)); 

fonctionnera. Notez que pour inspecter les éléments par la suite, vous devrez probablement utiliser le visitor pattern tel que documenté here.

Si votre objectif est d'avoir différents types de vecteurs qui ne peut contenir qu'un seul type de Point, vous pouvez utiliser:

template<typename T> using PointVector = std::vector<Point<T>>; // C++11 

// Now you can write: 
PointVector<int> my_vector; 

// Which is equivalent to: 
std::vector<Point<int>> my_vector; 

Ou, si 11 C++ est pas une option:

template<typename T> struct PointVector 
{ 
    typedef std::vector<Point<T> > Type; 
} 

Puis:

PointVector<int>::Type my_vector; 
+0

Merci pour la réponse complète. D'après ma compréhension Boost et C++ 11 ne sont pas dans les bibliothèques C++ standard, et j'écris du code qui sera exécuté sur les ordinateurs qui n'ont pas nécessairement ces paquets. Cependant, je cherche exactement votre première solution impliquant des variantes. Y a-t-il un moyen de le faire sans Boost? (Dites, comme l'autre réponse a suggéré.) – alexvas

+0

@alexvas: Si vous êtes à l'aise avec creuser dans le code Boost Variant, vous pouvez probablement le reproduire facilement. Ou vous pouvez peut-être extraire les fichiers de Boost (Boost a un outil pour en extraire proprement des sous-ensembles). Boost peut fonctionner sur de nombreuses plateformes, peut-être pouvez-vous l'expédier avec votre propre code (ou convaincre ceux qui décident de le faire?) – ereOn

2

Pour obtenir un seul type de vecteur, j'utiliser l'héritage:Remarque: l'héritage est juste un mécanisme permettant d'obtenir l'équivalent d'un typedef de modèle. Cela signifie que PointVector ne doit contenir aucun membre de données ni aucune fonction virtuelle. Cependant, la suggestion de @ ereOn est préférée, et est discutée dans la réponse à this question.

L'ancienne façon de réaliser une variante serait d'utiliser une union.

class IntOrDouble { 
    union { 
     int i; 
     double d; 
    }; 
    bool is_int; 
    bool is_double; 
public: 
    IntOrDouble() : is_int(false), is_double(false) {} 
    IntOrDouble (int x) : is_int(true), is_double(false) { i = x; } 
    IntOrDouble (double x) : is_int(false), is_double(true) { d = x; } 
    int operator = (int x) { 
     is_int = true; 
     is_double = false; 
     return i = x; 
    }; 
    double operator = (double x) { 
     is_int = false; 
     is_double = true; 
     return d = x; 
    }; 
    operator int() const { 
     if (is_int) return i; 
     if (is_double) return d; 
     return 0; 
    } 
    operator double() const { 
     if (is_double) return d; 
     if (is_int) return i; 
     return 0; 
    } 
}; 
typedef std::vector< Point<IntOrDouble> > PointVector; 

Mais tout cela semble un peu exagéré dans ce cas d'utilisation. Je voudrais juste utiliser des vecteurs de double tout autour, à moins que la mémoire soit vraiment serrée.

+0

Je ne vais pas downvote, mais hériter dans ce cas est faux pour plusieurs raisons. La raison la plus importante est que 'std :: vector' n'a pas été conçu pour être hérité publiquement. Je ne suis pas sûr de ce que dit la norme, mais je doute fortement qu'il y ait un destructeur virtuel par exemple, et cela pourrait mener à des problèmes subtils. Si quelque chose, il devrait être l'héritage privé et encore, je ne le recommanderais pas. – ereOn

+0

@ereOn: Merci pour l'entrée. J'ai utilisé l'héritage des conteneurs STL depuis longtemps maintenant, donc je trouve cela surprenant d'apprendre que ça pourrait être dangereux. Je serais intéressé par toute la documentation que vous trouvez qui soutient cela. Cordialement. – jxh

+0

@ereOn: J'ai clarifié ma réponse pour indiquer que l'héritage n'est utilisé que comme un moyen d'exécuter un template typedef. – jxh