1

Я реализовал шаблон базовый класса для шаблона наблюдателя,Переопределенная проблема указателя функции в шаблоне базового класса 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); 
}; 

я использую классы как этого

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

проблема здесь есть, компилятор не может вывести параметры шаблона, и я не мог явно задать параметры шаблона?

У кого-то есть идея?

EDIT: Проблема здесь - переопределенная функция вызова с параметрами шаблона. Функция «Испускать» работает правильно для других типов функций.

Использование этого шаблона

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

, кстати это C++.

+0

Почему вы не можете явно указать тип параметра шаблона? – Locksfree

+1

«... компилятор не может вывести параметры шаблона ...» Какое сообщение об ошибке? – sbi

+1

Мне трудно понять, что вы пытаетесь сделать. Добавьте дополнительные пояснения. Вы оставили определение Message и не упомянули, как ActionListener должен взаимодействовать с IEventListener. Ваши фрагменты кода не совсем понятны. Я думаю, вы пытаетесь эмулировать дженерики Java-стиля здесь, где T - тип класса, который происходит от IEventListener. Но я не уверен. – sellibitze

ответ

2

IEventListener::messageArrived перегружен, поэтому компилятор не может определить тип &IEventListener::messageArrived. Это может быть void (IEventListener::*)(Message*) или void (IEventListener::*)(ClientHandle*, Message*).

straighforward (и некрасиво) решением является явно отливать &IEventListener::messageArrived до нужного типа в месте вызова, как это:

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

или путем присвоения переменной нужного типа функции:

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

(я не сказал, что это некрасиво?)

параметр шаблона может также быть явно указано:

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

(Еще некрасиво)

Другое несовершенное решения вывести тип Signal от типа слушателя (T) и других параметров:

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

Это несовершенно, хотя, потому типы аргументов должны точно совпадать.

В зависимости от того, сколько изменений вы можете внести в дизайн, более простым решением было бы устранить двусмысленность, предоставив разные имена членам IEventListener. Вы также можете использовать уже существующую библиотеку сигналов/слотов, например Boost.Signals2

+0

Можете ли вы добавить явное кастинг здесь, потому что я не могу сделать cast.thx для всех. – Qubeuc

+0

Я добавил примеры для явного указания типа путем литья, используя промежуточную переменную или явно указывая параметр шаблона. –

+0

Я также добавил абзац в конце моего ответа с другими предложениями. –

0

Я немного запутался о вашем примере, вы вызываете

emit(&IEventListener::messageArrived, message); 

который я предполагаю, должен соответствовать

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

Но эта перегрузка emit принимает только один параметр, то, вы думаете, что используется параметр &IEventListener::messageArrived?

Помните, что IEventListener является параметром шаблона для класса ActionListener, а не для функции emit.

Когда я попытался это работает:

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

Я добавил несколько объяснений. Классы классов сообщений или Clienthandle не нужно объяснять, это всего лишь примеры классов. – Qubeuc