1

I mis en œuvre une classe de base de modèle pour motif d'observateur,problème de pointeur de fonction réécrite à la classe de base modèle C++

template<class T> 
class ActionListener 
{ 
public: 
    ActionListener(void);  
    virtual ~ActionListener(void);  
    void registerListener(T* listener);  
    void unregisterListener(T* listener); 

    template<typename Signal> 
    void emit(Signal signal); 

    template<typename Signal, typename Parameter> 
    void emit(Signal signal, const Parameter& parameter); 

    template<typename Signal, typename Parameter1, typename Parameter2> 
    void emit(Signal signal, 
       const Parameter1& parameter1, 
       const Parameter2& parameter2); 

private: 
    std::vector<T*> mListenerList; 
}; 

class IEventListener 
{ 
public: 
    virtual void messageArrived(Message* message); 
    virtual void messageArrived(ClientHandle* handle, Message* message); 
}; 

je suis en utilisant des cours comme celui-ci

emit(&IEventListener::messageArrived, message); 
emit(&IEventListener::messageArrived, mHandle, message); 

le problème est ici, le compilateur ne peut pas en déduire paramètres de modèle et je ne pouvais pas donner des paramètres de modèle explicitement?

Est-ce que quelqu'un a une idée?

EDIT: La fonction "Émettre" fonctionne correctement pour les autres types de fonctions.

L'utilisation de ce modèle est

class SampleClass : public ActionListener<IEventListener> 
{ 
//some stuff here 
//this class is observing events of IEventListener 
} 

par la façon dont cela est C++.

+0

Pourquoi ne pouvez-vous pas donner explicitement le type de paramètre template? – Locksfree

+1

"... le compilateur ne peut pas déduire de paramètres de modèle ..." Quel est le message d'erreur? – sbi

+1

J'ai du mal à comprendre ce que vous essayez de faire. S'il vous plaît ajouter plus d'explications. Vous avez omis la définition de Message et n'avez pas mentionné comment ActionListener doit interagir avec IEventListener. Vos fragments de code ne sont pas exactement explicites. Je pense que vous essayez d'émuler des génériques Java-style ici où T est un type de classe qui dérive de IEventListener. Mais je ne suis pas sur. – sellibitze

Répondre

2

IEventListener::messageArrived est surchargée, de sorte que le compilateur ne peut pas déterminer le type de &IEventListener::messageArrived. Il pourrait être void (IEventListener::*)(Message*) ou void (IEventListener::*)(ClientHandle*, Message*).

Le straighforward (et laid) solution consiste à couler explicitement &IEventListener::messageArrived au type désiré au niveau du site d'appel, comme ceci:

emit(static_cast<void (IEventListener::*)(Message*)>(&IEventListener::messageArrived), a_message_ptr); 

ou en affectant à une variable de type fonction désirée:

void (IEventListener::*func_ptr)(Message*) = &IEventListener::messageArrived; 
emit(func_ptr, a_message_ptr); 

(Ai-je dit qu'il était laid?)

pourrait aussi être spécifié explicitement paramètre de modèle:

emit<void (IEventListener::*)(Message*)>(&IEventListener::messageArrived, a_message_ptr); 

(toujours laid)

Une autre solution imparfaite est de déduire le type de Signal du type de l'auditeur (T) et les autres paramètres:

// Warning: untested. 
// For illustration purposes only 
template<class T> 
class ActionListener 
{ 
public: 
    //... 
    void emit(void (T::*signal)()); 

    template<class Arg1T> 
    void emit(void (T::*signal)(Arg1T), Arg1T); 

    template<class Arg1T, class Arg2T> 
    void emit(void (T::*signal)(Arg1T, Arg2T), Arg1T, Arg2T); 
}; 

Ceci est imparfait mais parce que les types d'arguments doivent correspondre exactement.

Selon la quantité de changements que vous pouvez apporter à la conception, une solution plus simple consisterait à supprimer l'ambiguïté en attribuant des noms différents aux membres de IEventListener. Vous pouvez également utiliser une bibliothèque de signaux/emplacements déjà existante, comme Boost.Signals2

+0

Pouvez-vous ajouter un casting explicite ici, parce que je ne peux pas faire le cast.thx pour tous. – Qubeuc

+0

J'ai ajouté des exemples pour spécifier explicitement le type en transtypant, en utilisant une variable intermédiaire, ou en indiquant explicitement le paramètre template. –

+0

J'ai également ajouté un paragraphe à la fin de ma réponse avec d'autres suggestions. –

0

Je suis un peu confus au sujet de votre exemple, vous appelez

emit(&IEventListener::messageArrived, message); 

que je suppose est censé correspondre

template <class Signal> 
ActionListener<T>::void emit(Signal signal); 

Mais cette surcharge de emit ne prend qu'un seul paramètre, ce Pensez-vous que le paramètre &IEventListener::messageArrived est utilisé? Rappelez-vous que IEventListener est le paramètre modèle pour la classe ActionListener et non pour la fonction emit.

Quand j'ai essayé cela, il fonctionne:

ActionListener<IEventListener> al; 
Message* message = 0; 
al.emit(message); 
+0

J'ai ajouté quelques explications. Les classes Message ou Clienthandle n'ont pas besoin d'être expliquées, ce ne sont que des exemples de classes. – Qubeuc

Questions connexes