2014-02-09 3 views
4

Я пытаюсь использовать шаблон шаблон в качестве параметра, все в порядке, когда я компилирую с лязгом, но когда я пытаюсь с GCC 4.8 У меня есть следующее сообщение об ошибке:Шаблон параметра шаблона с GCC

can't deduce a template for 'TReceiver' from non-template type 'DamageAnimationSystem'

Здесь моя ситуация: у меня есть программа, в которой классы могут подписаться на диспетчер событий для некоторых типов событий, но не для всех.

Чтобы сделать это, я наследовать от класса с определенным типом:

class DamageAnimationSystem : public Receiver<DamageEvent>, 
           public Receiver<HealthEvent> 

Здесь мой класс будет слушать «DamageEvent» и «HealthEvent», поэтому мне нужно, чтобы объявить виртуальные методы для этого типа событий :

DamageAnimationSystem::onEvent(const DamageEvent& event) {} 
DamageAnimationSystem::onEvent(const HealthEvent& event) {} 

И мне нужно, чтобы подписаться на это событие:

DamageAnimationSystem::DamageAnimationSystem() 
{ 
    eventManager->subscribe<DamageEvent>(this); 
    eventManager->subscribe<HealthEvent>(this); 
} 

Как я уже говорил, е все хорошо, когда я использую Clang, но когда я использую GCC, я получил приведенную выше ошибку.

Вот что я сделал:

Приемник:

class EBaseReceiver 
{ 
protected: 
    static std::size_t nextId; 
}; 

template <typename TEventData> 
class Receiver : public EBaseReceiver 
{ 
friend class EventManager; 
public: 
    virtual void onEventReceive(const TEventData& event) = 0; 
    static std::size_t getId() { return ID; } 
private: 
    static std::size_t ID; 
}; 

Событие:

struct BaseEvent 
{ 
protected: 
    static std::size_t nextId; 
}; 

template <typename T> 
struct Event : public BaseEvent 
{ 
    static std::size_t getId() { return ID; } 
    static std::size_t ID; 
}; 

**And finally the event manager:** 
template< class TEvent, template<class> class TReceiver> 
void EventManager::subscribe(TReceiver<TEvent>* receiver); 
{ 
    const std::size_t eventId = TEvent::getId(); 
    this->subscribers[eventId].push_back(receiver); 
} 

Я сделал моделирования в Интернете, чтобы результат теста: https://ideone.com/vZZhqN

Большое спасибо за вашу помощь!

PS: Мне нужна совместимость с GCC, потому что мне нужно использовать этот код с андроидом NDK, и нить не работала с clang на последнем NDK.

EDIT

Я пытаюсь использовать другой метод с стандом :: функцией и станд :: безвыходным:

Приемник:

class Receiver {}; 

Событие:

template <typename T> 
struct Event : public BaseEvent 
{ 
    friend class EventManager; 
    static std::size_t getId() { return ID; } 
private:    
    typedef std::function<void(const T& event)> EventCallback; 
    static std::size_t ID; 
    static std::vector<EventCallback> listeners; 
}; 

** EventManager **

//////////////////////////////////////////////////////////// 
template <typename TEvent> 
void emit(const TEvent& event) 
{ 
    const auto& listeners = TEvent::listeners; 
    for(const auto& listener : listeners) 
     listener(event); 
} 

//////////////////////////////////////////////////////////// 
template< class TEvent, class TReceiver> 
void subscribe(TReceiver* receiver) 
{ 
    TEvent::listeners.push_back(std::bind(&TReceiver::onEventReceive, receiver, std::placeholders::_1)); 
} 

Я получил следующее сообщение об ошибке на станд :: безвыходном:

No matching function for call to 'bind' 
Candidate template ignored: couldn't infer template argument '_Fp' 
Candidate template ignored: couldn't infer template argument '_Rp' 

Еще раз спасибо!

+0

Не могли бы вы добавить 'метод EventManager' который поднимает события? То, где вызываются виртуальные функции, и, там, где ошибки, вероятно, есть. Я думаю, что вы должны использовать виртуальное наследование в своих приемниках: вы наследуете от нескольких разных приемников, а vtable получателя должен отправить в правильный класс приемника, не так ли? – Manu343726

+0

OTOH есть апроксимации к этой проблеме, намного проще реализовать. Рассмотрим это: что на самом деле событие? Набор обратных вызовов и приемник - это просто обратный вызов. Но обратный вызов не является только функцией, может быть *** любым вызываемым объектом ***. Поэтому я предлагаю вам использовать 'std :: function' вместо классов приемника. Играя немного с концепцией, вы можете создать класс событий, который позволяет любым типам вызываемых объектов быть приемниками (указатели функций, lambdas, функторы, ** функции-члены **, глобальные функции и т. Д.). – Manu343726

+0

У вас действительно есть несколько типов 'Reciever'' TEMPLATE', которые вам нужно поддерживать? Удалите 'TReciever' и измените параметр на' Reciever <…> ' – Yakk

ответ

1

следующие компилирует (не ссылаются): https://ideone.com/EheCok

Я Явный шаблон аргумент, что путь:

eventManager.subscribe<HealthEvent, ::Receiver>(this); 
eventManager.subscribe<DamageEvent, ::Receiver>(this); 
+0

Спасибо! Он работает как шарм! – user30088

Смежные вопросы