I'm using the macros from this post looping through my arguments. Everything works great! However, is there a way to combine these two CCB_CREATE
and CCB_CREATE_MORE
?
I need to extract the first argument object_type
to write additional code. The additional object_type
s will be using the FOR_EACH
loop to insert into the map.
The compiler complaints when I only have one argument when using CCB_CREATE_MORE(Type1)
. To fix that I made another macro to handle that CCB_CREATE(Type1)
. Hoping to find a clever solution to combine these two into one elegant macro. Any ideas?
#define INSERT_LOADER_MAP(object_type) loader_map.insert(make_pair(#object_type, object_type##Loader::loader()))
#define CCB_CREATE_MORE(object_type,...) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
FOR_EACH(INSERT_LOADER_MAP,object_type,__VA_ARGS__); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
#define CCB_CREATE(object_type) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
INSERT_LOADER_MAP(object_type); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
A comma must separate each parameter. For portability, you should not have more than 31 parameters for a macro. The parameter list may end with an ellipsis (…).
3.3 Macro Arguments To invoke a macro that takes arguments, you write the name of the macro followed by a list of actual arguments in parentheses, separated by commas. The invocation of the macro need not be restricted to a single logical line—it can cross as many lines in the source file as you wish.
To create a macro with arguments, put them in parentheses separated by commas after the macro name, e.g. then BadSquare(3+4) would give 3+4*3+4, which evaluates to 19, which is probably not what we intended.
macro expansion possible specifying __VA_ARGS__ The '...' in the parameter list represents the variadic data when the macro is invoked and the __VA_ARGS__ in the expansion represents the variadic data in the expansion of the macro. Variadic data is of the form of 1 or more preprocessor tokens separated by commas.
The compiler is likely complaining about the trailing comma when the variadic arguments list is empty. GCC and Visual Studio compilers support the non-standard extension ##__VA_ARGS__
to suppress the trailing comma:
#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)
The Visual Studio compilers will also suppress the trailing comma even without the ##
extension.
See GCC documentation here, and Visual Studio documentation here.
If you need a standards-compliant solution, there is one detailed in an answer to this question.
So if you are using either gcc or Visual Studio, you should be able to use your original macro with this simple change:
#define CCB_CREATE(object_type,...) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
FOR_EACH(INSERT_LOADER_MAP,object_type,##__VA_ARGS__); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
Edit:
You would need to use the ##__VA_ARGS__
extension in the FOR_EACH()
macro as well, or the more elegant modification suggested by ugoren.
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, ##__VA_ARGS__), what, x, __VA_ARGS__)
In addition to Chris Olsen's suggestion, a slight change to the FOR_EACH
macro is needed:
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
As a result, FOR_EACH(X, a)
will become X(a)
(instead of X(a); X();
). This eliminates an empty INSERT_LOADER_MAP
invocation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With