宏调用中的 #ifdef 适用于 gcc,但不适用于 msvc

Posted

技术标签:

【中文标题】宏调用中的 #ifdef 适用于 gcc,但不适用于 msvc【英文标题】:#ifdef inside a macro call works with gcc but not with msvc 【发布时间】:2013-10-01 08:27:53 【问题描述】:

我有一个宏 TYPELIST,它接受可变参数。我想要类似的东西

typedef TYPELIST(A
                ,B
                ,C
                ,D
#ifdef BLA_
                ,E
#endif
                ,F)

这与 gcc 完美配合。但是,当我尝试使用 MSVC 编译它时,它会将 ifdef 和 endif 解析为宏参数。我知道一种方法是将宏调用放在 ifdef 中。但是,如果我有一个巨大的列表,并且如果我想根据定义的不同宏包含不同的类,那将变得乏味。这有什么特殊原因可以在 gcc 中而不是在 MSVC 中使用吗?

【问题讨论】:

是的,将预处理器指令放在宏调用中是不合法的 C++。如果您尝试这样做,编译器可以做他们喜欢的事情。如您所见,g++ 和 MSVC 做不同的事情。 @john,你的评论不应该是一个更好的答案吗? GCC 和 MSVC 的哪个版本? @AdriC.S.这是对他问题的回答,但不是对他问题的真正回答。也许其他人可以提出一个可行的解决方案。 gcc-4.7 和 cl-16.00.30319.01 【参考方案1】:

在宏中使用#ifdef 是不合法的。我有点惊讶 gcc 允许这样做。恐怕您必须将#ifdef 放在整个定义中,即

#ifdef BLA_
    typedef TYPELIST(a,b,c,d,e,f)
#else
    typedef TYPELIST(a,b,c,d,f)
#endif

【讨论】:

在格式错误的意义上它不是非法的,它只是有未定义的行为。所以 gcc 可以接受就好了。【参考方案2】:

根据标准(§16.3.4/3),“结果完全 宏替换的预处理标记序列不被处理为 一个预处理指令,即使它类似于一个,[...]"。如果 g++ 在这里处理#ifdef/#endif,这是一个错误 编译器(至少如果您要求符合标准, 例如与-std=...)。

【讨论】:

但它适用于 g++ 和 clang++。我还尝试使用-std=c++03 强制标准一致性,但它仍然没有抱怨。 其实不是错误,只是UB。 16.3/11(谈论类函数宏的参数):“如果在参数列表中存在预处理标记序列,否则它们将充当预处理指令,则行为未定义。” 啊,是的。 “扩展为预处理器指令”和预处理参数列表中的标记之间存在差异。因此,就标准而言,这不是错误;只是他们如何处理未定义行为的一个糟糕的选择(尽管它可能与他们如何标记化有关)。

以上是关于宏调用中的 #ifdef 适用于 gcc,但不适用于 msvc的主要内容,如果未能解决你的问题,请参考以下文章

如何为 C++ 智能感知引擎定义宏?

Application.Run 用于宏返回数组

在 GCC 中将 0 参数传递给可变参数宏失败,但仅在 C++ 中?

部分视图部分适用于 JQuery,但不完全适用于 C# ASP.Net MVC 5

编写适用于 iOS 和 Mac OS 的类

为啥我的 SFINAE 表达式不再适用于 GCC 8.2?