generating code *solved

Started by
8 comments, last by SiCrane 16 years, 2 months ago
this is related to my last thread "help with implementing strategy pattern"... but i hope thats fine... ive had a sitation alot of times where i have to define a function several times but with different amount of variables...

template <class T> boost::shared_ptr<T> Create(std::string id)
    {}
template <class T, typename P0> boost::shared_ptr<T> Create(std::string id, P0 p0)
    {}
template <class T, typename P0, typename P1> boost::shared_ptr<T> Create(std::string id, P0 p0, P1 p1)
    {}

etc...





but to write it like sthis to at least 8 parameters is not practical... especially when u have to change somehting to solve this i use some preprocessor tricks... to auto generate all these it would work like this... CreateGenerator.h

#include "GeneratorMacro.h"
template <class T, ENUM_GENERATOR_TYPENAME_PARAMS> boost::shared_ptr<T> Create(std::string id, ENUM_GENERATOR_PARAMS)





GeneratorMacro.h

/***************************************
	AUTOMATIC CODE GENERATION MACROS
----------------------------------------

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

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

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

#define GENERATE(text, n) text 

#ifndef GENERATOR_COUNT
	#define GENERATOR_COUNT 0
#endif

#define ENUM_DEFAULT_PARAMS(n)				BOOST_PP_ENUM_PARAMS(n, P)
#define ENUM_DEFAULT_PARAMSLOW(n)			BOOST_PP_ENUM_PARAMS(n, p)
#define ENUM_DEFAULT_TYPENAME_PARAMS(n)		BOOST_PP_ENUM_PARAMS(n, typename P)
#define ENUM_DEFAULT_BINARY_PARAMS(n)		BOOST_PP_ENUM_BINARY_PARAMS(n, P, p)
#define DEFAULT_REPEAT(n, x, text)			BOOST_PP_REPEAT(n, x, params)

#undef	ENUM_GENERATOR_PARAMS
#undef	ENUM_GENERATOR_PARAMSLOW
#undef	ENUM_GENERATOR_TYPENAME_PARAMS
#undef	ENUM_GENERATOR_BINARY_PARAMS
#undef	GENERATOR_REPEAT
#undef	GENERATOR_TYPELIST	

#if GENERATOR_COUNT == 0
	#define ENUM_GENERATOR_TYPENAME_PARAMS
	#define ENUM_GENERATOR_PARAMS			
	#define ENUM_GENERATOR_PARAMSLOW		
	#define ENUM_GENERATOR_BINARY_PARAMS	
	#define GENERATOR_REPEAT(x, text)	
	#define GENERATOR_GENERATOR_TYPELIST 
	#undef  GENERATOR_COUNT
	#define GENERATOR_COUNT 1 
#elif GENERATOR_COUNT == 1
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(1, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(1, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(1, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(1, P, p)
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(1, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_1(P0)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 2 
#elif GENERATOR_COUNT == 2
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(2, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(2, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(2, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(2, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(2, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_2(P0, P1)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 3 
#elif GENERATOR_COUNT == 3
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(3, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(3, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(3, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(3, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(3, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_3(P0, P1, P2)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 4 
#elif GENERATOR_COUNT == 4
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(4, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(4, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(4, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(4, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(4, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_4(P0, P1, P2, P3)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 5 
#elif GENERATOR_COUNT == 5
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(5, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(5, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(5, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(5, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(5, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_5(P0, P1, P2, P3, P4)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 6 
#elif GENERATOR_COUNT == 6
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(6, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(6, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(6, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(6, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(6, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_6(P0, P1, P2, P3, P4, P5)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 7 
#elif GENERATOR_COUNT == 7
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(7, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(7, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(7, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(7, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(7, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_7(P0, P1, P2, P3, P4, P5, P6)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 8 
#elif GENERATOR_COUNT == 8
	#define ENUM_GENERATOR_PARAMS				BOOST_PP_ENUM_PARAMS(8, P)
	#define ENUM_GENERATOR_PARAMSLOW			BOOST_PP_ENUM_PARAMS(8, p)
	#define ENUM_GENERATOR_TYPENAME_PARAMS		BOOST_PP_ENUM_PARAMS(8, typename P)
	#define ENUM_GENERATOR_BINARY_PARAMS		BOOST_PP_ENUM_BINARY_PARAMS(8, P, p)	
	#define GENERATOR_REPEAT(x, text)			BOOST_PP_REPEAT(8, x, params)
	#define GENERATOR_TYPELIST LOKI_TYPELIST_8(P0, P1, P2, P3, P4, P5, P6, P7)
	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT
#endif





CreateClass.h

template <class T> boost::shared_ptr<T> Create(std::string id)
    {}
        #include "GeneratorMacro.h"

	#undef GENERATOR_COUNT
	#define GENERATOR_COUNT 1

	#include GENERATE("CreateGenerator.h",1)
	#include GENERATE("CreateGenerator.h",2)
	





this would give me exactly the same code as above... but its ugly and i dont think its a good idea... would it be possible to do this another way? something like


#define num_params

GENERATE(num_params)
{
template <class T, ENUM_GENERATOR_TYPENAME_PARAMS> boost::shared_ptr<T> Create(std::string id, ENUM_GENERATOR_PARAMS)
}






[Edited by - Dragon_Strike on February 17, 2008 5:33:48 AM]
Advertisement
Quote:this is related to my last thread "help with implementing strategy pattern"


Strategy pattern doesn't in any way require this.

This type of approach is better suited for Lua, which has language-level support for variable function signatures.

For C++, there's two ways to get your desired behavior: Default values
class Foo {  Foo(int a = 10, bool b = true, const std::string & baz = "Hello");};


Or, if you need arbitrary extensible construction, make it explicit:
class Parameters {public:    template < class T >  T get( const std::string & name, T default_value )  {    T temp;    ParamType::const_iterator i = params.find(name);    return (i == params.end()) ? default_value : boost::lexical_cast<T>(i->second);  }private:  typedef std::map<std::string, std::string> ParamType;  ParamType params;};struct Foo {  Foo(const Parameters & p)    : a( p.get<int>("a", 10)    , b( p.get<bool>("b", true)    , c( p.get<std::string>("baz", "Hello")  { }private:  int a;  bool b;  std::string baz;};


And voila - extensible, flexible construction parameters.

For bonus points, boost::any can be used, keys can be of different type, you can add run-time inheritance between parameters so you inherit from one or another, you can provide facades, default values, etc....

No macros, no obscure template magic, no code generation....
Quote:Original post by Antheus
Quote:this is related to my last thread "help with implementing strategy pattern"


Strategy pattern doesn't in any way require this.



yea i realized that and implemented it with boost::function and boost::bind...

in this case its just an example of the problem...

and im unsure if your suggestionswould work well... id still have to define a function for each number of fuction parameters...


You're preprocessor stuff is somewhat inefficient. When you create a single function that takes a number of arguments you don't need to write out a special case for each number of arguments. You might want to take a look of some examples here.
Quote:Original post by SiCrane
You're preprocessor stuff is somewhat inefficient. When you create a single function that takes a number of arguments you don't need to write out a special case for each number of arguments. You might want to take a look of some examples here.


thx... that was just what i was looking for...

but one question... how would i do if the function is inside a class? as far as i understood the code to be repeated has to be alone in a file...

class A
{
tempalte <typename P0> Foo(T p0) {}
tempalte <typename P0, typename P1> Foo(P0 p0, P1 p1) {}
}

The inclusion happens as soon as the #include BOOST_PP_ITERATE() is done. If you want it performed inside a class, use the #include BOOST_PP_ITERATE() directive inside the class definition.
im still unsure how that would work....

A.h
#pragma onceclass A{	#if !BOOST_PP_IS_ITERATING				#include "boost/preprocessor/iteration/iterate.hpp"		#include "boost/preprocessor/repetition/enum_params.hpp"		#include "boost/preprocessor/repetition/enum_trailing_params.hpp"		#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 5, "A.h"))		#include BOOST_PP_ITERATE()			#elif BOOST_PP_ITERATION_DEPTH() == 1		#define NUM_ARGS BOOST_PP_FRAME_ITERATION(1)		template <class T BOOST_PP_ENUM_TRAILING_PARAMS(NUM_ARGS, class P)> boost::shared_ptr<T> Foo(std::string id BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(NUM_ARGS, P, p))		{}		#endif};


doesnt work... it never goes into the #elif block

im not sure why... but wouldnt #pragma once terminate the file iteration? how do i get around it?
When you use file iteration, don't use #pragma once. Use normal preprocessor include guards, but put them in the #if !BOOST_PP_IS_ITERATING section. The class A { }; should also probably be in that section as well.
i still dont get it working

#if !BOOST_PP_IS_ITERATING	#ifndef	_A	#define _A	#include "boost/preprocessor/iteration/iterate.hpp"	#include "boost/preprocessor/repetition/enum_params.hpp"	#include "boost/preprocessor/repetition/enum_trailing_params.hpp"     class A     {	#endif#elif BOOST_PP_ITERATION_DEPTH() == 1	#include BOOST_PP_ITERATE()	#define NUM_ARGS BOOST_PP_FRAME_ITERATION(1)         tempalte <BOOST_PP_ENUM_TRAILING_PARAMS(NUM_ARGS, class P)> Foo(BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(NUM_ARGS, P, p)) {}#endif#if !BOOST_PP_IS_ITERATING	#ifndef	_A     };#endif#endif


EDIT:: i tried with LOCAL_ITERATE and my actual code

	#define BOOST_PP_LOCAL_MACRO(N)	template <class T, BOOST_PP_ENUM_PARAMS(N, class P)>\		boost::shared_ptr<T> Register(std::string id, BOOST_PP_ENUM_BINARY_PARAMS(N, P, p))\						{\                           FactoryUnit<T>& Unit = GetFactoryUnit<T>();\	                   return Unit.Register(id, boost::bind(&T::Create, &Unit.prototype, BOOST_PP_ENUM_PARAMS(N, p)));\		}\																									#define BOOST_PP_LOCAL_LIMITS (1, 9)	#include BOOST_PP_LOCAL_ITERATE()


however i get:

error C2017: illegal escape sequence
error C2061: syntax error : identifier 'BOOST_PP_REPEAT_1_N'

[Edited by - Dragon_Strike on February 17, 2008 5:29:52 AM]
There's an example of this in the link:
#if !BOOST_PP_IS_ITERATING  #ifndef OBJECT_PROXY_BASE_H  #define OBJECT_PROXY_BASE_H    #include "calling_convention.h"  #include <boost/preprocessor/repetition/enum_binary_params.hpp>   template <typename T>  class ObjectProxyBase {    protected:      ObjectProxyBase() : ref_cnt(1) {}      ObjectProxyBase(const ObjectProxyBase & other) : object(other.object), ref_cnt(1) {}      ObjectProxyBase & operator=(const ObjectProxyBase & rhs) {        object = rhs.object;      }       #define BOOST_PP_ITERATION_PARAMS_1 (3, (0, MAX_ARGS, "object_proxy_base.h"))      #include BOOST_PP_ITERATE()       T object;      unsigned ref_cnt;        };  #endif#elif BOOST_PP_ITERATION_DEPTH() == 1  #define NUM_ARGS BOOST_PP_FRAME_ITERATION(1)  #if NUM_ARGS != 0    template <BOOST_PP_ENUM_PARAMS(NUM_ARGS, typename A)>    ObjectProxyBase(BOOST_PP_ENUM_BINARY_PARAMS(NUM_ARGS, A, a))      : object(BOOST_PP_ENUM_PARAMS(NUM_ARGS, a)), ref_cnt(1) {}  #endif#endif

This topic is closed to new replies.

Advertisement