类似函数的宏从带括号的模板参数列表中"窃取"逗号是否合法?

Dam*_*mon 4 c++ c-preprocessor

我很惊讶,为类似函数的宏提供一个带有两个模板参数的类型会导致编译器抱怨.

这个(概念上类似的)示例代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

让GCC(6.2.0)抱怨macro "p" passed 2 arguments, but takes just 1.

当然,预处理器是一个执行文本替换的预处理器,它不是真正的C++编译器,它可以理解模板或该语言的所有其他规则.

也许我通过期待预处理器识别尖括号而给出太多要求,但是至少在规范中明确提到了括号.

16.3(第10至12段)规定了最外面的括号,用于界定有界的令牌序列."最外层"一词表示预处理器可能还有其他(非最外层)括号.
此外,它明确指出"跳过中间匹配的左右括号对"以及"匹配内括号之间的逗号预处理标记不分离参数" - 这意味着如果我正确读取,那么至少最后一行应该在我的理解传递.

我理解错了什么?

小智 6

p((bar<int,int>))是一个有效的p宏调用宏调用,即(bar<int,int>).到目前为止你的理解是正确的.

不幸的是,它的扩展包括sizeof((bar<int,int>))并且sizeof不接受双重括号类型.

Variadic宏(C++ 11)在这里可以很好地作为替代方案.

#define p(...) printf("sizeof(" #__VA_ARGS__ ") = %u\n", sizeof(__VA_ARGS__));
Run Code Online (Sandbox Code Playgroud)