Virus721
Virus721

Reputation: 8315

C++ Curiously recurring template pattern, syntax error

I'm trying to write a template event class and keep as much code as possible inside this base class. I'm using the curiously recurring template pattern, but i'm not exactly sure about what i'm doing here.

template< class EventType >
class Event
{
protected:

    std::vector< EventType::Listener * > m_aListeners;

public:

    void operator += ( EventType::Listener * pListener )
    {
        m_aListeners.push_back( pListener );
    }

    void operator -= ( EventType::Listener * pListener )
    {
        std::vector< EventType::Listener * >::reverse_iterator revIter = m_aListeners.rbegin();
        for( ; revIter != m_aListeners.rend(); ++revIter )
            if( revIter == pListener )
            {
                m_aListeners.remove( revIter );
                break;
            }
    }

    void Trigger( EventType::Data * pData )
    {
        std::vector< EventType::Listener * >::iterator iter = m_aListeners.begin();
        for( ; iter != m_aListeners.end(); ++iter )
            CallListenert( iter, pData );
    }

    virtual void CallListener( EventType::Listener * pListener, EventType::Data * pData ) = 0;
};

And its subclass for a given event type :

class ConnectionSuccessEvent : public Event< ConnectionSuccessEvent >
{
public:

    class Data
    {
    public:
        Data( int iVal ) : m_iVal( iVal ) { }
    public:
        const int m_iVal;
    };

    class Listener
    {
    public:
        virtual ~Listener() { }
        virtual void OnConnectionSuccess( Data * pEventData ) = 0;
    };

    void CallListener( Listener * pListener, Data * pData )
    {
        pListener->OnConnectionSuccess( pData );
    }
};

And a class implementing the listener class :

class MyClass :  public ConnectionSuccessEvent::Listener
{
public:

    void OnConnectionSuccess( ConnectionSuccessEvent::Data * pEventData )
    {
        std::cout << "OnConnectionSuccess : " << pEventData->m_iVal << std::endl;
    }
};

Which i use as follows :

MyClass oMyClassInstance;

ConnectionSuccessEvent oOnConnectionSuccess;

oOnConnectionSuccess += & oMyClassInstance;
oOnConnectionSuccess += & oMyClassInstance;

ConnectionSuccessEvent::Data oData( 456 );
oOnConnectionSuccess.Trigger( & oData );

oOnConnectionSuccess -= & oMyClassInstance;
oOnConnectionSuccess -= & oMyClassInstance;

This is resulting in several compilations errors, the first one being :

Error 2 error C2059: syntax error : '>' c:\dev\eventtest\event.h 16

Which corresponds to the declaration of the vector m_aListeners.

I have two questions :

Thank you !

EDIT : I can't use C++11.

Upvotes: 0

Views: 136

Answers (1)

Virus721
Virus721

Reputation: 8315

I found an acceptably ugly way to do that !

Base event class containing the behaviour of the event objects.

template< class EventListenerType, class EventDataType >
class BaseEvent
{
private:

    std::vector< EventListenerType * > m_aListeners;

public:

    void operator += ( EventListenerType * pListener )
    {
        m_aListeners.push_back( pListener );
    }

    void operator -= ( EventListenerType * pListener )
    {
        // When nI is 0 and gets decremented (i.e would be < 0), it "underflows" and
        // becomes >= m_aListeners.size(), so we can detect that the last element (i.e 
        // the first in position ) has been treated when nI >= m_aListeners.size().

        for( size_t nI = m_aListeners.size() - 1; nI <= m_aListeners.size(); --nI )
        {
            if( m_aListeners[ nI ] == pListener )
            {
                m_aListeners.erase( m_aListeners.begin() + nI );
                break;
            }
        }
    }

    void Trigger( EventDataType * pData )
    {
        for( size_t nI = 0; nI < m_aListeners.size(); ++nI )
            m_aListeners[ nI ]->OnEvent( pData );
    }
};

And :

template< class EventDataType >
class EventListener
{
public:

    virtual ~EventListener() { }

    virtual void OnEvent( const EventDataType * pData ) = 0;
};

ConnectionSuccessEvent specific stuff :

class ConnectionSuccessEventData
{
public:
    const int m_iVal;
    ConnectionSuccessEventData( int iVal ) : m_iVal( iVal ) { }
};

typedef EventListener< ConnectionSuccessEventData > ConnectionSuccessEventListener;
typedef BaseEvent< ConnectionSuccessEventListener, ConnectionSuccessEventData > ConnectionSuccessEvent;

DataReceivedEvent specific stuff :

class DataReceivedEventData
{
public:
    const float m_fVal;
    DataReceivedEventData( float fVal ) : m_fVal( fVal ) { }
};

typedef EventListener< DataReceivedEventData > DataReceivedEventListener;
typedef BaseEvent< DataReceivedEventListener, DataReceivedEventData > DataReceivedEvent;

Listener class :

class MyClass : public ConnectionSuccessEventListener, public DataReceivedEventListener
{
public:

    void OnEvent( const ConnectionSuccessEventData * pData )
    {
        std::cout << "Connection success event : " << pData->m_iVal << std::endl;
    }

    void OnEvent( const DataReceivedEventData * pData )
    {
        std::cout << "Data received event : " << pData->m_fVal << std::endl;
    }
};

Usage :

MyClass oMyClassInstance;

ConnectionSuccessEvent oOnConnectionSuccess;
DataReceivedEvent oOnDataReceived;

oOnConnectionSuccess += & oMyClassInstance;
oOnDataReceived += & oMyClassInstance;
oOnConnectionSuccess += & oMyClassInstance;
oOnDataReceived += & oMyClassInstance;

ConnectionSuccessEventData oConnectionSuccessData( 123 );
oOnConnectionSuccess.Trigger( & oConnectionSuccessData );

DataReceivedEventData oDataReceivedData( 0.0f );
oOnDataReceived.Trigger( & oDataReceivedData );

oOnDataReceived += & oMyClassInstance;
oOnConnectionSuccess -= & oMyClassInstance;
oOnDataReceived += & oMyClassInstance;
oOnConnectionSuccess -= & oMyClassInstance;

Upvotes: 1

Related Questions