2010-12-12 6 views
0
template <class VertexType> 
class GraphMatrix 
{ 
}; 

template <class GraphType> 
class Graph 
{ 
typedef typename GraphType::VertexType VertexType; 
GraphType* graph_; 
void addVertex(VertexType vertex) 
{ 
} 
//... 
}; 
int main() 
{ 
    Graph <GraphMatrix <int> > graph; 
    return 0; 
} 

Voir si j'ajouter typedef VertexType VertexType;//A ligne à GraphMatrixclass ce code passera la compilation et travaillerai, sinon il donne erreur de compilation. Erreur: C2039: 'VertexType': n'est pas un membre de 'GraphMatrix'. Ma question est la suivante 'y at-il un moyen (syntaxe) de faire ci-dessus le code de travail sans ajouter cette ligne stupide //A'?Comment éviter typedef?

Répondre

1

Vous pouvez toujours écrire le nom complet de VertexType, le typedef est simplement un raccourci pour vous, ce qui porte ce nom dans la portée et vous permet d'écrire du code plus propre.

Donc, pas de dans ce cas, il n'y a pas d'autre moyen. Lorsque vous utilisez l'héritage, vous pouvez using BaseClass::something pour l'afficher dans portée.

-1

J'en doute.

Du point de vue du modèle Graph, le paramètre de modèle GraphType est juste un nom de type (dans ce cas, une « classe »). Donc, si Graph est instancié avec GraphType = GraphMatrix<int>, alors Graph ne peut même pas vérifier s'il a reçu une instance de modèle ou une classe "régulière". Par conséquent, il ne peut pas accéder à ses paramètres de modèle - car GraphType n'a même pas besoin de paramètres de modèle.

L'introduction du typedef dans GraphType enrichit chaque instance du modèle GraphMatrix avec les informations publiques sur le type exact avec lequel il a été instancié - ce qui est exactement ce que vous voulez obtenir.

+0

Non vrai - 'Graph' peut vérifier que' GraphType' est un modèle avec un paramètre par spécialisation. – jpalecek

+0

Mais ne devrait pas - il est préférable pour une implémentation de s'appuyer sur une constract "Je vais être instancié avec des classes qui ont un typedef' VertexType' "que" Je ne vais être instancié qu'avec des classes de templates qui arrivent toujours avoir son premier paramètre de template en tant que VertexType ". Utilisation de la spécialisation ici semble hackish à moi et viole le principe le moins d'étonnement, à mon humble avis. Je repose mon cas. – Kos

1

My question is follows 'is there a way (syntax) to make above code work without adding this stupid line //A

Je ne pense pas.

Cependant, il y a quelques problèmes avec votre code. GraphType est un nom dépendant et pour indiquer que GraphType::VertexType est un type que vous devez ajouter typename avant.

Toutefois, lorsque le modèle de classe est instancié pour GraphType = GraphMatrix <int>, le compilateur n'a pas pu trouver GraphMatrix <int>::VertexType et vous obtenez une autre erreur.

Ainsi, afin de corriger les erreurs modifier la définition de GraphMatrix à

template <class TVertexType> 
class GraphMatrix 
{ 
    public: 
    typedef TVertexType VertexType;  
}; 

ou quelque chose de similaire.

Code de travail complet here

+0

Oh, je viens d'oublier le nom de fichier. C'est la raison pour laquelle je n'ai pas copié mon code, mais écris ici - dans le forum textarea :) Donc, comme je comprends de toutes les réponses, il n'y a aucun moyen d'éviter typedefing dans GraphMatrix. Merci à tous pour vos réponses :) –

0

Si vous voulez obtenir l'argument d'une classe par un passé basé sur un modèle modèle-paramètre, vous devez limiter les types admissibles pour GraphType.Pour ce faire, la spécialisation:

template <class GraphType> 
class Graph; 

template <template <class> class GraphType, class VertexType> 
class Graph<GraphType<VertexType> > 
{ 
    ... // use GraphType<VertexType> as your graph, VertexType as your vertex type 
}; 

Vous pouvez même create a helper struct that will unpack the args for you:

template <class T> struct get_arg; 

template <template <class> class Tpl, class Arg> 
struct get_arg<Tpl<Arg> > 
{ 
    typedef Arg type; 
}; 

Notez cependant que cette solution est tout à fait inflexible - il ne permet que des modèles avec un paramètre comme arguments pour votre modèle de classe Graph (Imaginez ce que vous auriez fait si vous avez ajouté un paramètre à votre modèle GraphMatrix). Donc, il n'est pas normalement utilisé.

La solution ordinaire est d'ajouter typedefs à vos classes (comme vous le faites avec votre "ligne stupide"), ou mieux encore, en utilisant des classes de traits et en les spécialisant.