Damon Damon - 5 months ago 41
C++ Question

Is it legal for a function-like macro to "steal" commas from a parenthesed template argument list?

I was just surprised that providing a type with two template arguments to a function-like macro resulted in the compiler complaining.

This (conceptually similar) example code:

template<typename T> struct foo{};
template<typename T, U> struct bar{};
#define p(x) printf("sizeof(" #x ") = %u\n", sizeof(x));

int main()
p(foo<int>); // works, of course
p(bar<int,int>); // does not work
p((bar<int,int>)); // does not work either
return 0;

makes GCC (6.2.0) complain
macro "p" passed 2 arguments, but takes just 1

Well, of course, the preprocessor is a preprocessor doing text replacement, it's not a real C++ compiler which understands templates or all other rules of the language.

Maybe I'm asking too much by expecting that the preprocessor recognizes the angle brackets, granted... but at least parentheses are explicitly mentioned in the specification.

16.3 (paragraphs 10 to 12) states outermost parentheses delimiting the bounded sequence of tokens. The word "outermost" suggests that there may possibly also be further (not-outermost) parentheses which the preprocessor recognizes.

Also, it explicitly states "skipping intervening matched pairs of left and right parenthesis" as well as "comma preprocessing tokens between matching inner parentheses do not separate arguments" -- which means that if I am reading correctly, then at least the last line should in my understanding pass.

What am I understanding wrong?

hvd hvd

p((bar<int,int>)) is a valid invocation of the p macro with a single macro argument, which is (bar<int,int>). Your understanding so far is correct.

Unfortunately, its expansion includes sizeof((bar<int,int>)), and sizeof does not accept doubly-parenthesised types.

Variadic macros (C++11) work well here as an alternative.

#define p(...) printf("sizeof(" #__VA_ARGS__ ") = %u\n", sizeof(__VA_ARGS__));