2010-05-30 23 views
15

Je dois écrire un programme implémentant le modèle de conception de visiteur. Le problème est que la classe de visiteurs de base est une classe de modèle. Cela signifie que BaseVisited :: accept() prend une classe template comme paramètre et comme elle utilise 'this' et que j'ai besoin de 'this' pour pointer vers la bonne instance d'exécution de l'objet, elle doit aussi être virtuelle.
Je voudrais savoir s'il y a moyen de contourner ce problème.besoin d'un membre de modèle virtuel solution de contournement

template <typename T> 
class BaseVisitor { 
    public: 
    BaseVisitor(); 
    T visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
} 


class BaseVisited { 
    BaseVisited(); 
    template <typename T> 
    virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem 
    virtual ~BaseVisited(); 
} 
+1

Quel est le problème avec cela? –

+2

il ne compilera pas. http://stackoverflow.com/questions/2354210/template-member-function-virtual – yurib

+2

Le compilateur n'accepte pas les modèles dans les fonctions virtuelles. – Puppy

Répondre

16

Ce que vous devez faire est de séparer le BaseVisitor.

class BaseVisited; 
class BaseVisitorInternal { 
public: 
    virtual void visit(BaseVisited*) = 0; 
    virtual ~BaseVisitorInternal() {} 
}; 
class BaseVisited { 
    BaseVisited(); 
    virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); } 
}; 
template<typename T> class BaseVisitor : public BaseVisitorInternal { 
    void visit(BaseVisited* visited); 
}; 

Si vous avez besoin des classes dérivées de BaseVisited être trop basé sur un modèle et passer leurs bons types/Surcharges à visiter, vous êtes officiellement mort.

+0

Tu m'as battu dessus! :-) –

+3

Fondamentalement, il s'agit de [type erasure] (http://stackoverflow.com/questions/2354210/template-member-function-virtual/2354671#2354671). – sbi

+0

Je pense que je pourrais être officiellement mort ... :-P – NargothBond

4

je suis venu avec quelque chose de légèrement différent de celui DeadMG:

class BaseVisited; 

class IVisitor { 
    public: 
    virtual void visit(BaseVisited *visited) = 0; 
    virtual ~IVisitor(); 
}; 

template <typename T> 
class BaseVisitor : public IVisitor { 
    public: 
    BaseVisitor(); 
    virtual void visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
    virtual T result(); 
}; 


class BaseVisited { 
    public: 
    BaseVisited(); 
    virtual void accept(IVisitor *visitor) { visitor->visit(this); }; 
    virtual ~BaseVisited(); 
}; 

Le mien a une fonction de membre result() supplémentaire qui vous permet de récupérer le résultat de la dernière visite.

+0

Je ne pense pas que cela fonctionnera –

4

Vous ne pouvez pas déclarer/définir des fonctions virtuelles modélisées. La raison en est que le mécanisme de répartition virtuelle doit être connu lorsque le compilateur voit la définition de la classe de base, mais les modèles sont compilés à la demande. Avec l'implémentation de vtable commune, le problème est que le nombre d'entrées que le compilateur doit réserver pour la fonction virtuelle est indéfini (combien d'instanciations différentes du type peut-il y avoir?), Comme leur ordre . Si vous déclarez la classe:

class base { 
public: 
    virtual void foo(); 
    virtual int bar(); 
}; 

Le compilateur peut réserver deux entrées dans le vtable pour les pointeurs vers foo et bar dans le vtable et le vtable est parfaitement défini juste en inspectant la définition de classe. Cela ne peut pas être réalisé avec des fonctions modélisées.

+0

Je sais que c'est impossible et je comprends pourquoi, ma question était de trouver une solution qui n'implique pas un modèle de fonction virtuelle . merci quand même. – yurib

+0

@Yurib: vous voulez une solution et pourtant vous n'avez pas déclaré votre problème - J'ai demandé que dans un commentaire à la question: Qu'est-ce que vous voulez vraiment atteindre. Vous avez seulement posé des questions sur une solution potentielle qui ne fonctionne pas, pas sur le problème initial. –