Say we have a macro like this
#define FOO(type,name) type name
Which we could use like
FOO(int, int_var);
But not always as simply as that:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Of course we could do:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
which is not very ergonomic. Plus type incompatibilities have to be dealt with. Any idea how to resolve this with macro ?
If your preprocessor supports variadic macros:
Otherwise, it's a bit more tedious:
Just define
FOO
asThen invoke it always with parenthesis around the type argument, e.g.
It can of course be a good idea to exemplify the invocations in a comment on the macro definition.
There are at least two ways to do this. First, you can define a macro that takes multiple arguments:
if you do that you may find that you end up defining more macros to handle more arguments.
Second, you can put parentheses around the argument:
if you do that you may find that the extra parentheses screw up the syntax of the result.
The simple answer is that you can't. This is a side effect of the choice of
<...>
for template arguments; the<
and>
also appear in unbalanced contexts so the macro mechanism couldn't be extended to handle them like it handles parentheses. (Some of the committee members had argued for a different token, say(^...^)
, but they weren't able to convince the majority of the problems using<...>
.)Because angle brackets can also represent (or occur in) the comparison operators
<
,>
,<=
and>=
, macro expansion can't ignore commas inside angle brackets like it does within parentheses. (This is also a problem for square brackets and braces, even though those usually occur as balanced pairs.) You can enclose the macro argument in parentheses:The problem is then that the parameter remains parenthesized inside the macro expansion, which prevents it being read as a type in most contexts.
A nice trick to workaround this is that in C++, you can extract a typename from a parenthesized type name using a function type:
Because forming function types ignores extra parentheses, you can use this macro with or without parentheses where the type name doesn't include a comma:
In C, of course, this isn't necessary because type names can't contain commas outside parentheses. So, for a cross-language macro you can write:
If you can't use parentheses and you don't like Mike's SINGLE_ARG solution, just define a COMMA:
This also helps if you want to stringify some of the macro arguments, as in
which prints
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.