Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / Objective C

An Easy to Use Observer Pattern Implementation (No Inheritance Required)

Rate me:
Please Sign up or sign in to vote.
4.95/5 (21 votes)
26 Jan 20047 min read 88.8K   1.3K   41  
Observer Pattern implemented in a nice template model, easy to use as it does not require the classical inheritance and can easily decouple Subject and Observer
////////////////////////////////////////////////////////////////////////////////
// Observer Pattern Implementation
// 
// Copyright (c) 2004 Corneliu I. Tusnea
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the author be held liable for any damages arising from 
// the use of this software.
// Permission to use, copy, modify, distribute and sell this software for any 
// purpose is hereby granted without fee, provided that the above copyright 
// notice appear in all copies and that both that copyright notice and this 
// permission notice appear in supporting documentation.
//
// Notice: Contains parts of Alexandrescu's Loki Library (from the Rani Sharoni VC7 ported version)
//
//////////////////////////////////////////////////////////////////////////////////

#ifndef BLUE_OBSERVER_H_INCLUDED
#define BLUE_OBSERVER_H_INCLUDED

#pragma once

#include <list>
#include <algorithm>


namespace Blue{

// Part of Loki Library (c) Alexandrescu
template <typename T>
struct Type2Type
{   
    typedef T OriginalType;
    Type2Type(){} // VC7
};
// end Loki




#ifndef ASSERT
	#ifdef _DEBUG
		#include <crtdbg.h>
		#define ASSERT(f) _ASSERTE(f)
	#else
		#define ASSERT(f)
	#endif
#endif

// Just define this to a type with the size of your pointer type (32/64)
#ifndef INT_PTR
#define INT_PTR int
#endif

#pragma warning ( push )
#pragma warning ( disable: 4355 )	// warning C4355: 'this' : used in base member initializer list
#pragma warning ( disable: 4312 )	// C4312: 'type cast' : conversion from 'int' to 'int *' of greater size

// ******************************************************************
// General Stuff
class NullType{}; // just a no class

// Calculate the number of parameters 
template <unsigned I> struct ParamCount : ParamCount < I-1 >  {};
template <>			  struct ParamCount <0> {};

// Calculate the number of valid arguments (arguments!=NullType)
template <typename T> struct ArgCounter				{ enum {Count=1}; };
template <>			  struct ArgCounter <NullType>	{ enum {Count=0}; };

// ******************************************************************
// Function Detection Templates
// Define Template Functions used to identify number of valid arguments used in pointer to functions
// This is also used as the template for other template specializations
// 5 Params
template<typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
class FuncTypeOverload{
public:
	typedef void (_Observer::*_FuncPointType)( _Subject, _Param, _Param2, _Param3, _Param4, _Param5 );	// subject as param 
};
template<typename _Observer, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
class FuncTypeOverload < _Observer, NullType, _Param, _Param2, _Param3, _Param4, _Param5 > {
public:
	typedef void (_Observer::*_FuncPointType)( _Param, _Param2, _Param3, _Param4, _Param5 );	// no subject
};
// 4 Params
template<typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3, typename _Param4>
class FuncTypeOverload < _Observer, _Subject, _Param, _Param2, _Param3, _Param4, NullType > {
public:
	typedef void (_Observer::*_FuncPointType)( _Subject, _Param, _Param2, _Param3, _Param4 ); // subject as param
};
template<typename _Observer, typename _Param, typename _Param2, typename _Param3, typename _Param4>
class FuncTypeOverload < _Observer, NullType, _Param, _Param2, _Param3, _Param4, NullType > {
public:
	typedef void (_Observer::*_FuncPointType)( _Param, _Param2, _Param3, _Param4 ); // no subject
};
// 3 Params
template<typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3>
class FuncTypeOverload < _Observer, _Subject, _Param, _Param2, _Param3, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Subject, _Param, _Param2, _Param3 ); // subject as param
};
template<typename _Observer, typename _Param, typename _Param2, typename _Param3>
class FuncTypeOverload < _Observer, NullType, _Param, _Param2, _Param3, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Param, _Param2, _Param3 );	// no subject
};
// 2 Params
template<typename _Observer, typename _Subject, typename _Param, typename _Param2>
class FuncTypeOverload < _Observer, _Subject, _Param, _Param2, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Subject, _Param, _Param2 );		// subject as param
};
template<typename _Observer, typename _Param, typename _Param2>
class FuncTypeOverload < _Observer, NullType, _Param, _Param2, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Param, _Param2 );				// no subject
};
// 1 Param
template<typename _Observer, typename _Subject, typename _Param>
class FuncTypeOverload < _Observer, _Subject, _Param, NullType, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Subject, _Param );				// subject as param
};
template<typename _Observer, typename _Param>
class FuncTypeOverload < _Observer, NullType, _Param, NullType, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Param );						// no subject
};
// NO Params
template<typename _Observer, typename _Subject>
class FuncTypeOverload < _Observer, _Subject, NullType, NullType, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( _Subject );						// subject as param
};
template<typename _Observer>
class FuncTypeOverload < _Observer, NullType, NullType, NullType, NullType, NullType, NullType >{
public:
	typedef void (_Observer::*_FuncPointType)( );								// no subject
};



// ******************************************************************
// Represents the function inside the Observer. This class is only used for typedetection
// it's role is than taken over by TFunctionCallParams
template<typename _Observer, typename _Subject = NullType, typename _Param = NullType, typename _Param2 = NullType, typename _Param3 = NullType, typename _Param4 = NullType, typename _Param5 = NullType>
class TClientObserver
{
public:
	explicit TClientObserver( _Observer* pObserver, typename FuncTypeOverload<_Observer,_Subject,_Param,_Param2,_Param3,_Param4,_Param5>::_FuncPointType _FuncPoint )
	{
		Observer	= pObserver;
		FuncPoint	= _FuncPoint;
	};
	~TClientObserver()	{ };	// not needed to be virtual

	// not protected as this object has a very very short life
	typename FuncTypeOverload<_Observer,_Subject,_Param,_Param2,_Param3,_Param4,_Param5>::_FuncPointType	FuncPoint;
	_Observer*		Observer;
};

// Template functions used to ease detection of params of received functions when subscribed by the Observer
// NO Params
template <typename _Observer, typename _Subject>
TClientObserver<_Observer,_Subject>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject) )
{	return TClientObserver<_Observer,_Subject> ( pObserver, _FuncPoint ); }
template <typename _Observer>
TClientObserver<_Observer,NullType>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)() )
{	return TClientObserver<_Observer> ( pObserver, _FuncPoint ); }
// 1 Param
template <typename _Observer, typename _Subject, typename _Param>
TClientObserver<_Observer,_Subject,_Param>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject, _Param) )
{	return TClientObserver<_Observer,_Subject,_Param> ( pObserver, _FuncPoint ); }
template <typename _Observer, typename _Param>
TClientObserver<_Observer,NullType,_Param>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Param) )
{	return TClientObserver<_Observer,NullType,_Param> ( pObserver, _FuncPoint ); }
// 2 Params
template <typename _Observer, typename _Subject, typename _Param, typename _Param2>
TClientObserver<_Observer,_Subject,_Param,_Param2>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject, _Param, _Param2) )
{	return TClientObserver<_Observer,_Subject,_Param, _Param2> ( pObserver, _FuncPoint ); }
template <typename _Observer, typename _Param, typename _Param2>
TClientObserver<_Observer,NullType,_Param,_Param2>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Param, _Param2) )
{	return TClientObserver<_Observer,NullType,_Param, _Param2> ( pObserver, _FuncPoint ); }
// 3 Params
template <typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3>
TClientObserver<_Observer,_Subject,_Param,_Param2,_Param3>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject, _Param, _Param2, _Param3) )
{	return TClientObserver<_Observer,_Subject,_Param, _Param2, _Param3> ( pObserver, _FuncPoint ); }
template <typename _Observer, typename _Param, typename _Param2, typename _Param3>
TClientObserver<_Observer,NullType,_Param,_Param2,_Param3>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Param, _Param2, _Param3) )
{	return TClientObserver<_Observer,NullType,_Param, _Param2, _Param3> ( pObserver, _FuncPoint ); }
// 4 Params
template <typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3, typename _Param4>
TClientObserver<_Observer,_Subject,_Param,_Param2,_Param3,_Param4>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject, _Param, _Param2, _Param3, _Param4) )
{	return TClientObserver<_Observer,_Subject,_Param, _Param2, _Param3, _Param4> ( pObserver, _FuncPoint ); }
template <typename _Observer, typename _Param, typename _Param2, typename _Param3, typename _Param4>
TClientObserver<_Observer,NullType,_Param,_Param2,_Param3,_Param4>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Param, _Param2, _Param3, _Param4) )
{	return TClientObserver<_Observer,NullType,_Param, _Param2, _Param3, _Param4> ( pObserver, _FuncPoint ); }
// 5 Params
template <typename _Observer, typename _Subject, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
TClientObserver<_Observer,_Subject,_Param,_Param2,_Param3,_Param4,_Param5>	SubjectObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Subject, _Param, _Param2, _Param3, _Param4, _Param5) )
{	return TClientObserver<_Observer,_Subject,_Param, _Param2, _Param3, _Param4, _Param5> ( pObserver, _FuncPoint ); }
template <typename _Observer, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
TClientObserver<_Observer,NullType,_Param,_Param2,_Param3,_Param4,_Param5>	ClientObserver( _Observer* pObserver, void (_Observer::*_FuncPoint)(_Param, _Param2, _Param3, _Param4, _Param5) )
{	return TClientObserver<_Observer,NullType,_Param, _Param2, _Param3, _Param4, _Param5> ( pObserver, _FuncPoint ); }


// ******************************************************************
// Observer Function Call
// Just a base class for representing the call towards an observer
// is it to be used in the std::list of the SEventsList
class ObserverFunctionCallBase
{
protected:
	// Base class for the ObserverFunctionCallItem to be used in the list
	class FunctionCallItem
	{
	public:
		FunctionCallItem() {};
		virtual ~FunctionCallItem() {};
		virtual bool	IsSameFunction( INT_PTR* pObject, INT_PTR* pFunction ) = 0;	// test that one function pointer is the same with the one inside
	};
	typedef std::list< FunctionCallItem* >	LIST_OBS_FUNC_CALL;		// list of function calls to different observers
	typedef LIST_OBS_FUNC_CALL::iterator	LIST_OBS_FUNC_CALL_IT;

public:
	ObserverFunctionCallBase() {};
	virtual ~ObserverFunctionCallBase()
	{
		// Destroy All remainings
		for ( LIST_OBS_FUNC_CALL_IT it = m_ObserversFunc.begin(); it != m_ObserversFunc.end(); it++ )
		{
			FunctionCallItem *pObj = (*it);
			delete pObj;
		}
		m_ObserversFunc.clear();
	};
protected:
	LIST_OBS_FUNC_CALL			m_ObserversFunc;
};


// Base template for observer function call
// it detects number of valid, parameters, function to be called, validity of the parameters ...
template< typename _Subject, typename _Param = NullType, typename _Param2 = NullType, typename _Param3 = NullType, typename _Param4 = NullType, typename _Param5 = NullType >
class TObserverFunctionCallBase
	: public ObserverFunctionCallBase
{
	// Observer Function Call with details about the params and subject (Observer is NOT part of this class!!)
	template< typename _Subject, typename _Param = NullType, typename _Param2 = NullType, typename _Param3 = NullType, typename _Param4 = NullType, typename _Param5 = NullType >
	class TFunctionCallItem : public FunctionCallItem
	{
	public:
		TFunctionCallItem( _Subject pSubject )
		{
			m_pSubject = pSubject;
		};
		
		virtual void Call ( _Param, _Param2, _Param3, _Param4, _Param5 ) = 0;
	protected:
		_Subject			m_pSubject;
	};

public:
	// Class that realy represents the FunctionCall to an observer !!
	// this is the class that will readly do the call to the observer
	template< typename _Observer, typename _Subject, typename _Param = NullType, typename _Param2 = NullType, typename _Param3 = NullType, typename _Param4 = NullType, typename _Param5 = NullType >
	class TFunctionCallParams : public TFunctionCallItem < _Subject, _Param, _Param2, _Param3, _Param4, _Param5 >
	{
	public:
		// number of valid arguments (non NullType)
		const static size_t ArgCount	=	ArgCounter<_Param>::Count + ArgCounter<_Param2>::Count +
											ArgCounter<_Param3>::Count + ArgCounter<_Param4>::Count +
											ArgCounter<_Param5>::Count;

		// Receives an TClientObserver containing the details of the function defined by the Observer including the params and Subject
		TFunctionCallParams( const TClientObserver< _Observer, _Subject, _Param, _Param2, _Param3, _Param4, _Param5 > &theObs, _Subject pSubject )
			: TFunctionCallItem< _Subject, _Param, _Param2, _Param3, _Param4, _Param5 > ( pSubject )
		{
			m_pObserver = theObs.Observer;
			m_pFunction	= theObs.FuncPoint;
		}
		virtual void Call ( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5 )
		{	// delegate the call to the function with the correct number of param!!
			_Call<int> ( param, param2, param3, param4, param5, ParamCount<ArgCount>(), Type2Type<_Subject>() );
		}
		// just a test to see if the function to be received is the same function as the one we already have
		virtual bool	IsSameFunction( INT_PTR* pObject, INT_PTR* pFunction )
		{
			if (	pObject		== (INT_PTR*) m_pObserver &&
					pFunction	== (INT_PTR*)(*(INT_PTR*)& m_pFunction) )
					return true;
			return false;
		}
	protected:
		// Functions delegated acording to the number of params
		// (used when the Subject is not sent to the Observer) (Subject type is NullType)
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<0>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<1>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( param ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<2>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( param, param2 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<3>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( param, param2, param3 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<4>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( param, param2, param3, param4 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<5>, Type2Type<NullType> )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( param, param2, param3, param4, param5 ); }

		// Functions delegated acording to the number of params
		// Used when the Subject IS sent to the Observer
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<0>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<1>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject, param ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<2>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject, param, param2 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<3>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject, param, param2, param3 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<4>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject, param, param2, param3, param4 ); }
		template<typename T> void _Call( _Param param, _Param2 param2, _Param3 param3, _Param4 param4, _Param5 param5, ParamCount<5>, ... )
		{ ( ((_Observer*)m_pObserver)->*m_pFunction) ( (_Subject)m_pSubject, param, param2, param3, param4, param5 ); }

		_Observer*			m_pObserver;	// the one  ... the observer to be called
		// the function pointer as detected by the FuncTypeOverload classes (see above for the definition of the FuncTypeOverload)
		typename FuncTypeOverload<_Observer,_Subject,_Param,_Param2,_Param3,_Param4,_Param5>::_FuncPointType		m_pFunction;
	};

	// ******************************************************
	// Notify one observer of a specific event !!!

	// error C2664: 'void TObserverFunctionCallBase<_Subject,_Param,_Param2>::Notify(_Param,_Param2)' : cannot convert parameter 2 from 'NullType' to 'std::string'
	// in here it means you are not calling the correct function with the correct number of parameters !!
	inline void operator() ( )
	{
		Notify ( NullType(), NullType(), NullType(), NullType(), NullType() );
	};
	inline void operator() ( _Param p1 )
	{
		Notify ( p1, NullType(), NullType(), NullType(), NullType() );
	};
	inline void operator() ( _Param p1, _Param2 p2 )
	{
		Notify ( p1, p2, NullType(), NullType(), NullType() );
	};
	inline void operator() ( _Param p1, _Param2 p2, _Param3 p3 )
	{
		Notify ( p1, p2, p3, NullType(), NullType() );
	};
	inline void operator() ( _Param p1, _Param2 p2, _Param3 p3, _Param4 p4 )
	{
		Notify ( p1, p2, p3, p4, NullType() );
	};
	inline void operator() ( _Param p1, _Param2 p2, _Param3 p3, _Param4 p4, _Param5 p5 )
	{
		Notify ( p1, p2, p3, p4, p5 );
	};


	inline void Notify ( )
	{
		Notify ( NullType(), NullType(), NullType(), NullType(), NullType() );
	};
	inline void Notify ( _Param p1 )
	{
		Notify ( p1, NullType(), NullType(), NullType(), NullType() );
	};
	inline void Notify ( _Param p1, _Param2 p2 )
	{
		Notify ( p1, p2, NullType(), NullType(), NullType() );
	};
	inline void Notify ( _Param p1, _Param2 p2, _Param3 p3 )
	{
		Notify ( p1, p2, p3, NullType(), NullType() );
	};
	inline void Notify ( _Param p1, _Param2 p2, _Param3 p3, _Param4 p4 )
	{
		Notify ( p1, p2, p3, p4, NullType() );
	};
	inline void Notify ( _Param p1, _Param2 p2, _Param3 p3, _Param4 p4, _Param5 p5 )
	{
		for ( LIST_OBS_FUNC_CALL::iterator it = m_ObserversFunc.begin(); it != m_ObserversFunc.end(); it++ )
		{
			TFunctionCallItem<_Subject,_Param,_Param2,_Param3,_Param4,_Param5> *pCall = (TFunctionCallItem<_Subject,_Param,_Param2,_Param3,_Param4,_Param5>*) (*it);
			pCall->Call ( p1, p2, p3, p4, p5 );
		}
	};
};



// The Observer that maintains the list of observers on ONE sigle function !!!
// this is one of the main point of the system
template<typename _Subject, typename _Param = NullType, typename _Param2 = NullType, typename _Param3 = NullType, typename _Param4 = NullType, typename _Param5 = NullType>
class TSubjectEvent
	: public TObserverFunctionCallBase< _Subject*, _Param, _Param2, _Param3, _Param4, _Param5 >
{
public:
	TSubjectEvent( )	// used in combination with the macros to define statically linked events
	{
		m_pParentFnc	= 0;
		m_pSubject		= 0;
	};
	TSubjectEvent( _Subject *pSubject, INT_PTR *pFnc )
	{
		m_pParentFnc	= pFnc;
		m_pSubject		= pSubject;
	};
	virtual ~TSubjectEvent(){};

	// If you get the error:
	// error C2784: 'void Blue::TSubjectEvent<_Subject,_Param,_Param2,_Param3,_Param4,_Param5>::operator +=(Blue::TClientObserver<_Observer2,_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> &)' : could not deduce template argument for 'Blue::TClientObserver<T1,T2,_Param,_Param2,_Param3,_Param4,_Param5> &' from ''unknown-type''
	// it means you forgot to prefix the ClientObserver( ... ) call with the namespace Blue::
	// your call has to look like:
	// subject.Events( CSubject::Event ) += Blue::ClientObserver ( &observer, CObserver::HandleEvent );

	// _Subject2 allowed as param only if it's a 
	template<class _Observer, class _Subject2>
	void operator+=( TClientObserver<_Observer, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> &obsNew )
	{
		ASSERT(m_pParentFnc);	// not correctly initialized (you missed the INIT_EVENT macro from your constructor ??)
		ASSERT(m_pSubject);		// not correctly initialized (you missed the INIT_EVENT macro from your constructor ??)

		// Uncomment this to have extensive subject type cast testing
		//_Subject2 pTest = dynamic_cast<_Subject*> ( m_pSubject );
		// if this fails during compilation, you are trying to do something like:
		// b.Events( A::Event ) += ClientObserver ( C, C::HandleEvent ); and
		// C::HandleEvent is defined as ( B* b, ... ); - and this is not realy allowed as it implied cast from A to B when B is the derived class

		//_Subject2 pSub = m_pSubject;
		//_Subject::SubjectTypeName *pSub = m_pSubject;

		//m_ObserversFunc.push_back ( new TFunctionCallParams<_Observer, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> ( obsNew, (_Subject2)m_pSubject ) );
		Add<_Observer,_Subject2> ( obsNew, Type2Type<_Subject2>() );
		/* Note: if you get an error in this line
		it means you are trying to add a function with the wrong prototype to this event chain!!
		Check again your parameters. Maybe the original event function params has been changed or your event function
		is not correctly defined as:
		// Event in Subject object has to be defined as:
		void functionname ( parametertype param );
		// Event in Observer object has to be defined as
		void functionname ( SubjectClass *pObject, parametertype param );
		// Note: FunctionName from the Subject and Observer can differ !!
		*/
	}
	template<typename _Observer, typename _Subject2>
		void Add ( TClientObserver<_Observer, NullType, _Param, _Param2, _Param3, _Param4, _Param5> &obsNew, Type2Type<NullType> )
	{
		m_ObserversFunc.push_back ( new TFunctionCallParams<_Observer, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> ( obsNew, NullType() ) );
	}
	template<typename _Observer, typename _Subject2>
		void Add ( TClientObserver<_Observer, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> &obsNew, ... )
	{
		m_ObserversFunc.push_back ( new TFunctionCallParams<_Observer, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> ( obsNew, (_Subject2)m_pSubject ) );
	}

	template<class _Observer2, class _Subject2>
	void operator-=( TClientObserver<_Observer2, _Subject2, _Param, _Param2, _Param3, _Param4, _Param5> &obsOld )
	{
		for ( LIST_OBS_FUNC_CALL_IT it = m_ObserversFunc.begin(); it != m_ObserversFunc.end();  )
		{
			FunctionCallItem *pObj = (*it);
			it++;	// move iterator otherwise it will get invalidated
			if ( pObj->IsSameFunction ( (INT_PTR*)obsOld.Observer, (INT_PTR*)(*(INT_PTR*)& obsOld.FuncPoint) ) )
			{
				m_ObserversFunc.remove ( pObj );
				delete pObj;
			}
		}
	}

	bool TestParentFunc ( INT_PTR* _FuncPoint )
	{
		return (_FuncPoint == m_pParentFnc);
	}
protected:
	INT_PTR					*m_pParentFnc;
	_Subject				*m_pSubject;
};

// ***************************************************************
// The Real Class that represents the events attached to a class
template<typename _Subject>
class SubjectEvents
{
	typedef std::list< Blue::ObserverFunctionCallBase* >		LIST_SUBJEV;
	typedef LIST_SUBJEV::iterator										LIST_SUBJEV_IT;

public:
	SubjectEvents(_Subject *pParent) { m_pParent = pParent; };
	virtual ~SubjectEvents()
	{
		// Destroy the list of events !
		for ( LIST_SUBJEV_IT it = m_Events.begin(); it != m_Events.end(); it++ )
		{
			Blue::ObserverFunctionCallBase *pObj = (*it);
			delete pObj;
		}
		m_Events.clear();
	}

	// Errors while compiling those functions usually means that you missed some parameters while trying to notify an event
	// check your call and the number of parameters!!!

	// Note: operator() and function Event have the same implementation !!!
	// No Params
	template<typename _Subject2>
	Blue::TSubjectEvent<_Subject2>& Event ( void (_Subject2::*_FuncPoint)() )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,NullType,NullType,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 1 Param
	template<typename _Subject2, typename _Param>
	Blue::TSubjectEvent<_Subject2,_Param>& Event ( void (_Subject2::*_FuncPoint)(_Param) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,NullType,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 2 Params
	template<typename _Subject2, typename _Param, typename _Param2>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2>& Event ( void (_Subject2::*_FuncPoint)(_Param,_Param2) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 3 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3>& Event ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,NullType,NullType> ( pTestFuncPoint );
	}
	// 4 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3, typename _Param4>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4>& Event ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3,_Param4) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,_Param4,NullType> ( pTestFuncPoint );
	}
	// 5 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5>& Event ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3,_Param4,_Param5) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> ( pTestFuncPoint );
	}


	// No Params
	template<typename _Subject2>
	Blue::TSubjectEvent<_Subject2>& operator() ( void (_Subject2::*_FuncPoint)() )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,NullType,NullType,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 1 Param
	template<typename _Subject2, typename _Param>
	Blue::TSubjectEvent<_Subject2,_Param>& operator() ( void (_Subject2::*_FuncPoint)(_Param) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,NullType,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 2 Params
	template<typename _Subject2, typename _Param, typename _Param2>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2>& operator() ( void (_Subject2::*_FuncPoint)(_Param,_Param2) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,NullType,NullType,NullType> ( pTestFuncPoint );
	}
	// 3 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3>& operator() ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,NullType,NullType> ( pTestFuncPoint );
	}
	// 4 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3, typename _Param4>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4>& operator() ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3,_Param4) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,_Param4,NullType> ( pTestFuncPoint );
	}
	// 5 Params
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5>& operator() ( void (_Subject2::*_FuncPoint)(_Param,_Param2,_Param3,_Param4,_Param5) )
	{
		INT_PTR *pTestFuncPoint = (INT_PTR*)(*(INT_PTR*)&_FuncPoint);
		return GetReg<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> ( pTestFuncPoint );
	}

protected:
	template<typename _Subject2, typename _Param, typename _Param2, typename _Param3, typename _Param4, typename _Param5>
	Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5>& GetReg( INT_PTR *pTestFuncPoint )
	{
		// Check if this is already an event, if not add it to the list of existing events !
		for ( LIST_SUBJEV_IT it = m_Events.begin(); it != m_Events.end(); it++ )
		{	// Quite unsafe this: it<_Subject,_Param>  - change it !!!
			Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> *pObs = (Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5>*) (*it);
			if ( pObs->TestParentFunc ( pTestFuncPoint ) )
			{	// this is the one!!
				return *pObs;
			}
		}
		Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> *pNew = new Blue::TSubjectEvent<_Subject2,_Param,_Param2,_Param3,_Param4,_Param5> ( (_Subject2*)m_pParent, pTestFuncPoint );
		m_Events.push_back ( pNew );
		return *pNew;
	}

	_Subject		*m_pParent;
	LIST_SUBJEV		m_Events;
};


}	// namespace Blue
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Technical Lead OneSaas - Cloud Integrations Made Easy
Australia Australia

Comments and Discussions