views:

264

answers:

2

hi, I implemented a template base class for observer pattern,

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);
};

i am using classes like this

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

the problem here is, compiler cannot deduce template parameters and i couldn't gave template parameters explicitly?

Do someone have an idea ??

EDIT: Problem here is overridden function calling with template parameters."Emit" function works correctly for other function types.

Usage of this pattern is

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

by the way this is C++.

A: 

I'm a bit confused about your example, you're calling

emit(&IEventListener::messageArrived, message);

which I assume is supposed to match

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

But this overload of emit takes only one parameter, what do you think that the &IEventListener::messageArrived parameter is used for?

Remember that IEventListener is the template parameter for the class ActionListener and not for the emit function.

When I tried this it works:

ActionListener<IEventListener> al;
Message* message = 0;
al.emit(message);
Motti
i added some explanations.Message or Clienthandle classes are no need to explain, they are just example classes.
Qubeuc
+2  A: 

IEventListener::messageArrived is overloaded, so the compiler can't determine the type of &IEventListener::messageArrived. It could be void (IEventListener::*)(Message*) or void (IEventListener::*)(ClientHandle*, Message*).

The straighforward (and ugly) solution is to explicitely cast &IEventListener::messageArrived to the desired type at the call site, like this:

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

or by assigning to a variable of the desired function type:

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

(Did I say it was ugly?)

The template parameter could also be explicitly specified:

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

(Still ugly)

Another imperfect solution is to deduce the type of Signal from the type of the listener (T) and the other parameters:

// 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);
};

This is imperfect though because the arguments types must match exactly.

Depending how much change you can make in the design, a simpler solution would be to remove the ambiguity by giving different names to the members of IEventListener. You could also use an already existing signals/slots library, like Boost.Signals2

Éric Malenfant
Can you add explicit casting here, because i cannot do the cast.thx for all.
Qubeuc
I added examples for explicitly specifying the type by casting, using an intermediate variable, or explicitly stating the template parameter.
Éric Malenfant
I also added a paragraph at the end of my answer with other suggestions.
Éric Malenfant
thx for response.
Qubeuc