Sign in to follow this  

Implementing command design pattern *solved

This topic is 3586 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im trying to implement the command design pattern... or something similar... my implementation works great... the problem ive got is that i have to create one seperate command class for each number of parameters the command has to store... i solved this with some preprocessor tricks... but im not sure if its good idea ... and if not how i could do it in some other way... i dont want to retype a class for each parameter type because that would make it very time consuming to modify the implementation.... soo basily this is how it looks right now... im using the loki and boost library should i keep it? Command.h
/*****************************************
				COMMAND
-----------------------------------------
Stores a member function pointer and paramaters 
to be called later.

class A
{
   int void DoSomething(int, int) {}
}

Example: Command<int, int>(&A::DoSomething, 1, 1) MyCommand;	// Stores function
		 MyCommand();	// Calls function

By: Robert Nagy
*****************************************/
#pragma once 

#include "GeneratorMacro.h"

#include "boost/tuple/tuple.hpp"
#include "loki/TypeList.h"

namespace drone
{
	template <class R>
	class BaseCommand
	{
	public:
		virtual R* operator()() = 0;
	protected:
		R* prototype;
	};

	template <class R, class TList>
	class Command{};

	template <class R>
	class Command<R, Loki::NullType> : public BaseCommand<R>
	{		
		typedef R* (R::*CommandFunc)();	
	public:

		explicit Command(CommandFunc commandFunc) 
		: commandFunc_(commandFunc)	
		{}

		R* operator()() 
		{ 
			return (prototype->*commandFunc_)(); 
		}

	private: 	
		CommandFunc commandFunc_;
	};
	
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 1

	#include GENERATE("CommandGenerator.h",1)
	#include GENERATE("CommandGenerator.h",2)
	#include GENERATE("CommandGenerator.h",3)
	#include GENERATE("CommandGenerator.h",4)
	#include GENERATE("CommandGenerator.h",5)
	#include GENERATE("CommandGenerator.h",6)
	#include GENERATE("CommandGenerator.h",7)
	#include GENERATE("CommandGenerator.h",8)

} // namespace drone



// CommandGenerator.h
/***************************************
	COMMAND GENERATOR
----------------------------------------

Generates all command classes upto 8 function parameters

By: Robert Nagy
****************************************/


#include "GeneratorMacro.h"

#define SET_PARAM_TUPLE(z, n, text)		boost::get<n>(text) = BOOST_PP_CAT(p, 0);	
#define GET_PARAM_TUPLE(z, n, text)		BOOST_PP_COMMA_IF(n) boost::get<n>(text)

template <class R, ENUM_DEFAULT_TYPENAME_PARAMS>
class Command<R, TYPELIST> : public BaseCommand<R>
{
	typedef boost::tuple<ENUM_DEFAULT_PARAMS> Parameters;
	typedef R* (R::*CommandFunc)(ENUM_DEFAULT_PARAMS);	
public:

	explicit Command(CommandFunc commandFunc, ENUM_DEFAULT_BINARY_PARAMS) 
	: commandFunc_(commandFunc)	
	{
		DEFAULT_REPEAT(SET_PARAM_TUPLE, params);
	}

	R* operator()() 
	{ 
		return (prototype->*commandFunc_)(DEFAULT_REPEAT(GET_PARAM_TUPLE, params)); 
	}

private: 	
	Parameters params;
	CommandFunc commandFunc_;
};



// Generator Macro
/***************************************
	AUTOMATIC CODE GENERATION MACROS
----------------------------------------

Automaticly generated parameters are formatted
P0 p0, P1 p1 etc...

By: Robert Nagy
****************************************/

#include "boost/preprocessor.hpp"

#define GENERATE(text, n) text 

#ifndef GENERATOR_COUNT
	#define GENERATOR_COUNT 0
#endif

#undef	ENUM_DEFAULT_PARAMS
#undef	ENUM_DEFAULT_TYPENAME_PARAMS
#undef	ENUM_DEFAULT_BINARY_PARAMS
#undef	DEFAULT_REPEAT
#undef	TYPELIST	

#if GENERATOR_COUNT == 0
	#define ENUM_DEFAULT_TYPENAME_PARAMS
	#define ENUM_DEFAULT_PARAMS()			
	#define ENUM_DEFAULT_BINARY_PARAMS()	
	#define DEFAULT_REPEAT(x, text)	
	#define TYPELIST 
	#undef  GENERATOR_COUNT
	#define GENERATOR_COUNT 1 
#elif GENERATOR_COUNT == 1
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(1, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(1, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(1, P, p)
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(1, x, params)
	#define TYPELIST LOKI_TYPELIST_1(P0)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 2 
#elif GENERATOR_COUNT == 2
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(2, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(2, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(2, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(2, x, params)
	#define TYPELIST LOKI_TYPELIST_2(P0, P1)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 3 
#elif GENERATOR_COUNT == 3
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(3, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(3, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(3, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(3, x, params)
	#define TYPELIST LOKI_TYPELIST_3(P0, P1, P2)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 4 
#elif GENERATOR_COUNT == 4
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(4, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(4, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(4, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(4, x, params)
	#define TYPELIST LOKI_TYPELIST_4(P0, P1, P2, P3)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 5 
#elif GENERATOR_COUNT == 5
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(5, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(5, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(5, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(5, x, params)
	#define TYPELIST LOKI_TYPELIST_5(P0, P1, P2, P3, P4)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 6 
#elif GENERATOR_COUNT == 6
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(6, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(6, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(6, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(6, x, params)
	#define TYPELIST LOKI_TYPELIST_6(P0, P1, P2, P3, P4, P5)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 7 
#elif GENERATOR_COUNT == 7
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(7, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(7, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(7, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(7, x, params)
	#define TYPELIST LOKI_TYPELIST_7(P0, P1, P2, P3, P4, P5, P6)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 8 
#elif GENERATOR_COUNT == 8
	#define ENUM_DEFAULT_PARAMS				BOOST_PP_ENUM_PARAMS(8, P)
	#define ENUM_DEFAULT_TYPENAME_PARAMS	BOOST_PP_ENUM_PARAMS(8, typename P)
	#define ENUM_DEFAULT_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(8, P, p)	
	#define DEFAULT_REPEAT(x, text)			BOOST_PP_REPEAT(8, x, params)
	#define TYPELIST LOKI_TYPELIST_8(P0, P1, P2, P3, P4, P5, P6, P7)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT
#endif



[Edited by - Dragon_Strike on February 16, 2008 3:39:07 PM]

Share this post


Link to post
Share on other sites
ok ive tried implemnting it with boost::function and boost::bind

here is the command class


template <class R, class T>
class Command
{
public:

explicit Command(boost::function<R* (T*)> commandFunc)
{
commandFunc_ = commandFunc;
}

R* operator()()
{
return commandFunc_(&prototype);
}

private:
CommandFunc boost::function<R* (T*)>;
T prototype;
};





and its called like this

class A
{
void Create(int val) {return new A;}
};

Command<A, A>(boost::bind(&A::Create, 1)) creator;
creator();


in my understanding (i havent rly understood boost::bind) is that u can write
T theclass;
boost::function<void (int)> f = bind(T::function, 100);
f(&theclass); // is the same as function(100)

however i get some compile errors...

Error 9 error C2440: 'return' : cannot convert from 'A(` c:\program\boost\boost_1_34_1\boost\function\function_template.hpp 134 Design 1 test

Warning 2 warning C4180: qualifier applied to function type has no meaning; ignored c:\program\boost\boost_1_34_1\boost\bind.hpp 1575 Design 1 test

whats causing this?

[/source]

Share this post


Link to post
Share on other sites
Quote:
Original post by Dragon_Strike
ok ive tried implemnting it with boost::function and boost::bind

here is the command class
*** Source Snippet Removed ***

and its called like this

class A
{
void Create(int val) {return new A;}
};

Command<A, A>(boost::bind(&A::Create, 1)) creator;
creator();


You're missing an argument. Which A is the Create() method called on?

function<void (int)> f = bind(&A::Create, some_A_instance, 1);
f(); // calls some_A_instance.Create(1);

EDIT: the above actually calls Create(1) on a *copy* of some_A_instance. Pass a pointer or use boost::ref()/cref() if you don't want copies made.

I really wouldn't bother with an extra layer around boost::function (i.e. your Command class). It's just unnecessary fluff.

[Edited by - the_edd on February 16, 2008 3:30:39 PM]

Share this post


Link to post
Share on other sites

This topic is 3586 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this