C++ VC++;vs GCC预处理器

C++ VC++;vs GCC预处理器,c++,gcc,visual-c++,macros,c-preprocessor,C++,Gcc,Visual C++,Macros,C Preprocessor,长话短说,gcc和vc++预处理器在相同的输入下有不同的输出。vc++中的变量宏似乎在传递给另一个宏时不会进行“参数匹配”(如果是正确的术语)。 例如: #define MACRO(a, ...) head:a, tail:MACRO_OTHER(__VA_ARGS__) #define MACRO_OTHER(a, ...) head:a, tail:__VA_ARGS__ 与 gcc输出: head:1, tail:head:2, tail:3,4,5 vc++输出: h

长话短说,gcc和vc++预处理器在相同的输入下有不同的输出。vc++中的变量宏似乎在传递给另一个宏时不会进行“参数匹配”(如果是正确的术语)。 例如:

#define MACRO(a, ...)        head:a, tail:MACRO_OTHER(__VA_ARGS__)
#define MACRO_OTHER(a, ...)  head:a, tail:__VA_ARGS__

gcc输出:

head:1, tail:head:2, tail:3,4,5
vc++输出:

head:1, tail:head:2,3,4,5, tail:
显然
MACRO\u OTHER
中的
a
2,3,4,5
的可变参数部分为空。 考虑到这一点,有没有办法创建一个vc++来替代下面的宏(它在gcc中非常有用)

它基本上会为每个参数追加
\u argK

例如:

VA_TYPES_WITH_ARGS(int, bool, float)
将扩展到

int _arg3, bool _arg2, float _arg1
任何帮助都将不胜感激


相关预处理器问题:


通过使用Boost,您可以以一种合理的交叉编译器方式完成这项工作(并且可以接受更多的参数,而无需启动额外的工作),我可以告诉您,Boost花了这么多时间查看标题,它有许多解决问题的方法,例如:

#define VA_TYPES_WITH_ARGS(...)   \
    BOOST_PP_ENUM(                \
        BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),    \
        VA_TYPES_WITH_ARGS_MACRO,               \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
    )

#define VA_TYPES_WITH_ARGS_MACRO(z, n, data)       \
    BOOST_PP_TUPLE_ELEM(n, data) BOOST_PP_CAT(     \
        _arg,                                      \
        BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(data), n) \
    )                                              

VA_TYPES_WITH_ARGS(int, bool, float) //int _arg3 , bool _arg2 , float _arg1
第一个宏枚举变量参数(
ENUM
),为每个变量调用第二个宏并添加连接逗号。它从可变数据中形成一个元组,以提供给第二个宏

第二种形式是元素(
TUPLE\u ELEM
),后面是
\u arg
,与
size-n
SUB
)连接(
size
),其中
size
是变量数据中的元素数(作为元组提供给宏)(
TUPLE\u size


一种适用于VC++并与GCC分离的独立方法是:

#define EXPAND(...) __VA_ARGS__
#define LPAREN (
#define RPAREN )
现在,不要使用像
x(\uu-VA\u-ARGS\uuu)
这样的宏,而是像这样使用它:
EXPAND(x-LPAREN\uu-VA\u-ARGS\uu-RPAREN)

这迫使VC++预处理器比通常情况下更晚地扫描参数

您应该能够组合这两种形式,将编译器特定的位放在一个地方


注意到,不能有一个标准的C++答案:您依赖于<代码> x()(代码)>是一个没有参数的宏调用。这不是标准C++中预处理器的工作方式:如果

x
是一个可变宏,
x()
使用一个参数调用宏,并且该参数为空。此外,您还可以省略变量的参数:标准C++也不允许。如果宏定义为
#define FOO(x,…)
,则将其作为
FOO(1)
调用是无效的。由于不可能有一个标准的方法,希望各种方法都必须是特定于编译器的,这对您来说不是什么问题。

VC++在涉及C99时受到了严重的限制。在Boost.Preprocessor中,您可以看到各种变通方法。无论如何,如果我没有弄错的话,你可以使用Boost的
Boost\u PP\u ENUM
宏来完成你想要的工作。@chris但是VC++的目标是C++11,它提供了与C99 wrt可变宏和空宏参数相同的功能。至少,如果一些有效的C++11在VC++中不起作用,那么VC++很有可能被修复以使其起作用。事实上,C99并非如此。:)@hvd、目标和实现是完全不同的事情。只要看看所有出现的可变模板问题。无论如何,C99和C++11之间的预处理器是相同的,减去一些较小的东西,如
,不是吗?@chris哦,当然,我没有对此提出异议,并且修改了我之前的评论,以使我的观点更清楚。顺便说一句,你正在使用。谢谢,这正是我想要的。但我忘了提到,如果没有提供参数,它应该扩展为零。这个实现扩展到
\u arg1
@vim,我真的想不出比在第一个宏中使用一些作为
BOOST\u PP\u IF
的条件更简单的方法了,没有任何东西作为真分支,这是假分支。我已经尝试过了,但问题是,没有参数的宏和只有一个参数的宏的参数大小都是1,因此很难判断在这种情况下我们应该测试什么。@vim,您应该测试
ISEMPTY(\uu VA\u ARGS\uuu)
。在没有参数的情况下调用宏时,会给宏一个空参数。@vim,是的,我的建议是错误的。我忘记了,只要将现有宏放入
BOOST\u PP\u IF
,它就会放入额外的逗号,这意味着
BOOST\u PP\u IF
会有额外的参数。我要么用可变数据调用现有宏,要么调用
BOOST\u PP\u TUPLE\u EAT()
的结果,它只会忽略参数并扩展为零。
#define VA_TYPES_WITH_ARGS(...)   \
    BOOST_PP_ENUM(                \
        BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),    \
        VA_TYPES_WITH_ARGS_MACRO,               \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
    )

#define VA_TYPES_WITH_ARGS_MACRO(z, n, data)       \
    BOOST_PP_TUPLE_ELEM(n, data) BOOST_PP_CAT(     \
        _arg,                                      \
        BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(data), n) \
    )                                              

VA_TYPES_WITH_ARGS(int, bool, float) //int _arg3 , bool _arg2 , float _arg1
#define EXPAND(...) __VA_ARGS__
#define LPAREN (
#define RPAREN )