Я пытаюсь использовать шаблон шаблон в качестве параметра, все в порядке, когда я компилирую с лязгом, но когда я пытаюсь с 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'
Еще раз спасибо!
Не могли бы вы добавить 'метод EventManager' который поднимает события? То, где вызываются виртуальные функции, и, там, где ошибки, вероятно, есть. Я думаю, что вы должны использовать виртуальное наследование в своих приемниках: вы наследуете от нескольких разных приемников, а vtable получателя должен отправить в правильный класс приемника, не так ли? – Manu343726
OTOH есть апроксимации к этой проблеме, намного проще реализовать. Рассмотрим это: что на самом деле событие? Набор обратных вызовов и приемник - это просто обратный вызов. Но обратный вызов не является только функцией, может быть *** любым вызываемым объектом ***. Поэтому я предлагаю вам использовать 'std :: function' вместо классов приемника. Играя немного с концепцией, вы можете создать класс событий, который позволяет любым типам вызываемых объектов быть приемниками (указатели функций, lambdas, функторы, ** функции-члены **, глобальные функции и т. Д.). – Manu343726
У вас действительно есть несколько типов 'Reciever'' TEMPLATE', которые вам нужно поддерживать? Удалите 'TReciever' и измените параметр на' Reciever <…> ' – Yakk