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

时间:2014-01-03 21:35:43

标签: c++ c++11 c-preprocessor language-lawyer

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

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

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

MYMACRO(long[2], {1, 2})

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

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

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

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

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

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

更新

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

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

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

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

1 个答案:

答案 0 :(得分:13)

您可以使用__VA_ARGS__

#define MYMACRO(T,...) literal<T>(__VA_ARGS__);

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

#define UNWRAP(...) __VA_ARGS__
#define MYMACRO(T,A) literal<T>(UNWRAP A);

现在你可以使用

MYMACRO( long[2], ({1, 2}) )

更新回答

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

#define BRACED_INIT_LIST(...) {__VA_ARGS__}
#define MYMACRO(T,A) literal<T>(BRACED_INIT_LIST A);

并致电

MYMACRO( long[2], (1, 2) )

这是恕我直言,与典型的宏调用样式一致。

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

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

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