是否可以将括号括起的初始化程序作为宏参数传递?

And*_*ost 21 c++ language-lawyer c-preprocessor c++11

我有一个我称之为的函数:

literal<long[2]>({1, 2});
Run Code Online (Sandbox Code Playgroud)

我想写一个扩展到这个语句的宏,例如:

MYMACRO(long[2], {1, 2})
Run Code Online (Sandbox Code Playgroud)

不幸的是,预处理器不知道大括号匹配,所以它看到三个参数(第二个和第三个分别是{12}).

这是预处理器的已知限制,最简单的解决方案通常是在宏调用中添加额外的括号(如果可能).

但是,在这种情况下,将括号括起的初始化器放在括号内似乎改变了它的含义:

literal<long[2]>(({1, 2}));

(g++ 4.8) error: left operand of comma operator has no effect [-Werror=unused-value]
Run Code Online (Sandbox Code Playgroud)

这是GCC错误还是设计错误?有什么方法可以实现我想要的吗?

更新

我可能应该更清楚原始问题的措辞.预处理器没有永久改变(甚至可变参数宏长期以来都是GCC扩展).在这种情况下实际的解决方法是有用的,但它们也是众所周知的,并不是我想要达到的目的.

我真的想知道是否有任何东西被添加到C++ 11中以专门解决这个问题(或者是疏忽?).考虑到在整个语言中使用大括号括起来的列表,宏观调用中的大括号的古怪处理现在似乎是一个更大的问题.

我特别恼火的是,将括号括在括号内的初始化列表中会改变它在用作函数参数时的解析方式.函数调用是否有任何其他参数不能括号?在编写将参数传递给函数的宏时,似乎是特殊情况.

我真的希望有人可以指出这是一个GCC错误,或解释为什么将括号括在括号内的初始化列表中必须改变其含义.

Dan*_*rey 13

你可以使用__VA_ARGS__:

#define MYMACRO(T,...) literal<T>(__VA_ARGS__);
Run Code Online (Sandbox Code Playgroud)

如果您有更多参数,可以使用间接:

#define UNWRAP(...) __VA_ARGS__
#define MYMACRO(T,A) literal<T>(UNWRAP A);
Run Code Online (Sandbox Code Playgroud)

现在你可以使用了

MYMACRO( long[2], ({1, 2}) )
Run Code Online (Sandbox Code Playgroud)

更新的答案

如果您愿意,也可以使用圆括号替换宏调用中的花括号:

#define BRACED_INIT_LIST(...) {__VA_ARGS__}
#define MYMACRO(T,A) literal<T>(BRACED_INIT_LIST A);
Run Code Online (Sandbox Code Playgroud)

并打电话

MYMACRO( long[2], (1, 2) )
Run Code Online (Sandbox Code Playgroud)

这是恕我直言,与典型的宏调用风格一致.

关于你的其他问题的一些话:预处理器对语言一无所知(C,C++,C++ 11),因此不应该关心符号的特殊含义.它跟踪圆括号,但几乎所有其他东西都只是令牌.

我也认为这不是标准委员会的疏忽,因为重点应放在大多数情况下使预处理器的使用是多余的.您是否考虑过其他(非宏)技术MYMACRO?此外,剩余用例的解决方案(如上所示)当然是可行的.

最后,它肯定不是GCC中的错误,因为编译器只是简单地实现了标准所说的内容.