stdxPreprocessor.h Macros
Couple of macros to help with preprocessor code generation. Only really needed in a couple very specific instances. The following example shows how to use these variables to create a set of templated functions which create vectors of different lengths.
#define CREATE_PUSHBACKS_LOOP_BODY( count ) vec.push_back( v ## count ); #define CREATE_VECTOR_LOOP_BODY( count ) template < class T > std::vector<T> make_vector( STDX_PP_PARAM_LIST( count, const T& v ) ) { std::vector<T> vec; STDX_PP_LOOP_C1( count, CREATE_PUSHBACKS_LOOP_BODY ); return vec; } STDX_PP_LOOP( 5, CREATE_VECTOR_LOOP_BODY );
The macro call STDX_PP_LOOP( 5, CREATE_LOOP_BODY ) calls the macro CREATE_VECTOR_LOOP_BODY five times - each time passing the current loop counter in as the only argument to CREATE_VECTOR_LOOP_BODY. The macro CREATE_VECTOR_LOOP_BODY expands to be a templated function definition. The parameter list is created using the STDX_PP_PARAM_LIST macro - this macro creates a comma separated list which looks like this:
stdx::vector<T> make_vector( const T& v1, const T& v2, const T& v3 ... )
The calls to push_back are created using STDX_PP_LOOP which in turn calls CREATE_PUSHBACKS_LOOP_BODY count times. Note that we must use the explicit STDX_PP_LOOP_C1 version of STDX_PP_LOOP. This is because recursive definitions will not be properly expanded my the preprocessor. If we used STDX_PP_LOOP inside CREATE_VECTOR_LOOP_BODY then the macro call STDX_PP_LOOP( 5, CREATE_VECTOR_LOOP_BODY ) would have a second call to STDX_PP_LOOP inside of it which would not be properly expanded. There are a couple of additional versions of STDX_PP_LOOP with unique suffixes to help this problem.
So the end result is five templated functions which allow one to create vectors using the following syntax.
stdx::vector<int> vec1 = make_vector( 1 ); stdx::vector<int> vec2 = make_vector( 1, 2 ); stdx::vector<int> vec3 = make_vector( 1, 2, 3 ); stdx::vector<int> vec4 = make_vector( 1, 2, 3, 4 ); stdx::vector<int> vec5 = make_vector( 1, 2, 3, 4, 5 );
Now what if we wanted to create these type of make functions for vectors, lists, or any other container with push_back defined? We could use a template argument of the make function to specify the return type, but this create rather length syntax, and these make functions will often be used to create function call arguments inline. So instead we can just create separate functions for the key container types.
#define CREATE_PUSHBACKS_LOOP_BODY( count ) _c.push_back( v ## count ); #define CREATE_VECTOR_LOOP_BODY( count, container, functionName ) template < class T > container<T> functionName( STDX_PP_PARAM_LIST( count, const T& v ) ) { container<T> _c; STDX_PP_LOOP_C1( count, CREATE_PUSHBACKS_LOOP_BODY ); return _c; }
STDX_PP_LOOP( 5, CREATE_VECTOR_LOOP_BODY, std::vector, make_vector ); STDX_PP_LOOP( 5, CREATE_VECTOR_LOOP_BODY, std::list, make_list );
This code creates five templated functions to create vectors with one to five elements, and five templated functions to create lists with one to five elements. Notice that we can pass an arbitrary number of arguments into the loop body.
The beauty of all this is that it is trivial to generate many make container functions for one to maybe 50 arguments. There is no other type-safe way to do this other than have all these functions, but the macros reduce code duplication.