Original Post
I've been dabbling in using the preprocessor to auto-generate code. What I have written compiles and works great on VC++ 7.1, but when I tried compiling under g++ 3.4.2 I'm getting compile errors. After spending a full day getting nowhere, I'm hoping one of you g++ and preprocessor gurus may be able to help me out. ;) I've whittled the code down to a bare minimum to reproduce the error and added a bunch of comments to hopefully explain how it works. Anyone familiar with the Boost Preprocessor should be able to understand what the code is doing. But let me briefly explain: I wrote, for the sake of an example, a function which create will create any object the user specifies, like so: As mentioned, this compiled perfectly in VC++ 7.1, but I get the following errors in g++ 3.4.2: ../test4.cpp:75:1: macro "MACRO_REPEAT_1" passed 5 arguments, but takes just 3 ../test4.cpp:75: error: expected nested-name-specifier before "ClassType" ../test4.cpp:75: error: ISO C++ forbids declaration of
template<typename ClassType>
ClassType *CreateObject()
{
return new ClassType;
}
I'd like to use function template overloading to allow the user to pass any number of constructor parameters to this function, like so:
template<typename ClassType, typename A1>
ClassType *CreateObject(A1 a1)
{
return new ClassType(a1);
}
template<typename ClassType, typename A1, typename A2>
ClassType *CreateObject(A1 a1, A2 a2)
{
return new ClassType(a1, a2);
}
Etc. However, instead of rewriting this function 16 times to allow 16 parameters I am instead using the preprocessor do that work. Below is a full source code example which does just that, and compiles fine in VC++ 7.1.
#include <iostream>
using namespace std;
// Commonly used pre-defined characters to seperate repeating code.
// For exmple, the comma seperate is used when repeating function
// arguments (ie, Function(A1 a1, A2 a2, A3 a3, ...) )
//
// The empty seperator is used when there doesn't need to be any
// characters between repeating code, such as repeating functions.
#define MACRO_EMPTY_SEPERATOR
#define MACRO_COMMA_SEPERATOR ,
// Commonly used pre-defined code to be repeated. For example, the
// MACRO_FUNCTION_PARAMETER is used to repeat function parameters
// (ie, Function(A1 a1, A2 a2, A3 a3, ...) ).
#define MACRO_TEMPLATE_PARAMETER(num) typename A##num
#define MACRO_FUNCTION_PARAMETER(num) A##num a##num
#define MACRO_FUNCTION_ARGUMENT(num) a##num
// The perform the actual repetition. Each macro will continuously
// call the preceding macro until the MACRO_REPEAT_0 is called, at
// which point each macro will write the seperator followed by the
// macro, passing the repitition number.
#define MACRO_REPEAT_0(begin_seperator, seperator, macro)
#define MACRO_REPEAT_1(begin_seperator, seperator, macro) begin_seperator macro(0)
#define MACRO_REPEAT_2(begin_seperator, seperator, macro) MACRO_REPEAT_1(begin_seperator, seperator, macro) seperator macro(1)
#define MACRO_REPEAT_3(begin_seperator, seperator, macro) MACRO_REPEAT_2(begin_seperator, seperator, macro) seperator macro(2)
#define MACRO_REPEAT_4(begin_seperator, seperator, macro) MACRO_REPEAT_3(begin_seperator, seperator, macro) seperator macro(3)
// User called macros that uses the above macros to perform the
// desired work. MACRO_LIST is primarily used to list template
// or function arguments, where each argument is seperated by
// a comma (ie, Function(A1 a1, A2 a2, A3 a3, ...) ).
// MACRO_LIST_APPEND does the same as MACRO_LIST, except it is
// used to append arguments onto an existing argument, thus all
// code is preceded by a comma (ie, Function(int x, A1 a1, A2 a2, ...) ).
// MACRO_REPEAT simply repeats code not using any seperating
// characters.
#define MACRO_LIST(num, macro) MACRO_REPEAT_##num(MACRO_EMPTY_SEPERATOR, MACRO_COMMA_SEPERATOR, macro)
#define MACRO_LIST_APPEND(num, macro) MACRO_REPEAT_##num(MACRO_COMMA_SEPERATOR, MACRO_COMMA_SEPERATOR, macro)
#define MACRO_REPEAT(num, macro) MACRO_REPEAT_##num(MACRO_EMPTY_SEPERATOR, MACRO_EMPTY_SEPERATOR, macro)
// This creates a multiple CreateObject function using function
// template overloading. Basically, it allows a user to specify
// the object the function will create as well as any number
// of parameters to pass to that objects constructor. When the
// macros unroll this function, it will look similar to this:
//
// template<typename ClassType>
// ClassType *CreateObject()
// {
// return new ClassType();
// }
//
// template<typename ClassType, typename A1>;
// ClassType *CreateObject(A1 a1)
// {
// return new ClassType(a1);
// }
//
// template<typename ClassType, typename A1, typename A2>
// ClassType *CreateObject(A1 a1, A2 a2)
// {
// return new ClassType(a1, a2);
// }
// ...
//
// Note the macro below uses the \ to span multiple lines,
// but the source tags are removing them.
#define CREATEOBJECT(num)
template<typename ClassType MACRO_LIST_APPEND(num, MACRO_TEMPLATE_PARAMETER)>
ClassType *CreateObject(MACRO_LIST(num, MACRO_FUNCTION_PARAMETER))
{
return new ClassType( MACRO_LIST(num, MACRO_FUNCTION_ARGUMENT) );
}
// Generate 3 instances of this function, one which takes no
// constructor params, one which takes one param, and the
// last which takes two constructor parameters.
MACRO_REPEAT(3, CREATEOBJECT)
int main (int argc, char *argv[])
{
// Create an integer, passing 42 as a constructor parameter
int *ptr = CreateObject<int>(42);
cout << *ptr << endl;
return(0);
}
ClassType' with no type ../test4.cpp:75: error: expected >' before "MACRO_REPEAT_1" ../test4.cpp:75: error: expected constructor, destructor, or type conversion before '*' token ../test4.cpp:75: error: expected ;' before '*' token ../test4.cpp:75:1: macro "MACRO_REPEAT_1" passed 4 arguments, but takes just 3 ../test4.cpp:75:1: macro "MACRO_REPEAT_1" passed 4 arguments, but takes just 3 ../test4.cpp: In function int main(int, char**)': ../test4.cpp:83: error: no matching function for call to `CreateObject(int, int)' *** Errors occurred during this build *** Now, the strange thing is that if I change the MACRO_REPEAT(3, CREATEOBJECT) line and to create just TWO CreateObject functions (ie, MACRO_REPEAT(2, CREATEOBJECT)) then the code compiles and runs fine. But repeating code more than twice to allow 2 or more constructor parameters to be passed causes the errors displayed above. Anyone have any ideas what the issue could be??? - Houdini [Edited by - Houdini on September 13, 2005 9:41:26 AM]