Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template of template parameter with GCC

I'm trying to use template of template as parameter, everything is ok when I compile with clang but when I try with GCC 4.8 I have the following error:

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

Here is my situation: I've got a program where classes can subscribe to the event manager for some type of events but not all.

To do that, I inherit from a class with a specific type:

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

Here, my class will listen "DamageEvent" and "HealthEvent" so I need to declare virtual methods for this type of events:

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

And I need to subscribe to this event:

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

As I said before, everything is ok when I use Clang but when I use GCC I've got the error given above.

Here is what I've done:

Receiver:

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

Event:

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

I've made the simulation online to test result : https://ideone.com/vZZhqN

Thanks a lot for your help!

PS: I need compatibility with GCC because I need to use this code with android NDK and thread didn't work with clang on last NDK.

EDIT

I'm trying to use another method with std::function and std::bind:

Receiver:

class Receiver {};

Event:

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

I've got the following error on std::bind:

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'

Thanks again!

like image 693
user30088 Avatar asked Nov 02 '22 05:11

user30088


1 Answers

The following compiles (don't link): https://ideone.com/EheCok

I explicit the template argument that way:

eventManager.subscribe<HealthEvent, ::Receiver>(this);
eventManager.subscribe<DamageEvent, ::Receiver>(this);
like image 171
Jarod42 Avatar answered Nov 15 '22 05:11

Jarod42