gcc C++ 14 与 msvc++ 2015 中的级联宏

Posted

技术标签:

【中文标题】gcc C++ 14 与 msvc++ 2015 中的级联宏【英文标题】:Cascaded macros in gcc C++14 vs msvc++ 2015 【发布时间】:2016-07-21 20:34:40 【问题描述】:

我有以下代码在 msvc 2015 下工作:

#define CLASS_JS_PSG_PROPERTY_EX(PROPERTY, VALUE) \
static bool Get##PROPERTY(/*irrelevant params here...*/) \
 \
...
 some particular code
...
    return true; \


#define CLASS_JS_PSG_PROPERTY(VALUE) \
CLASS_JS_PSG_PROPERTY_EX(##VALUE, VALUE)

...

#define kProp 1

CLASS_JS_PSG_PROPERTY_EX(Version, kProp)

CLASS_JS_PSG_PROPERTY(kProp)

这应该定义名为 GetVersionGetkProp 的方法。

现在,这在 gcc C++14(实际上是 TDM-GCC-64)下会出现以下错误:

pasting "(" and "kProp" does not give a valid preprocessing token

应该如何编写才能在gcc C++14msvc 2015下编译?

【问题讨论】:

试试CLASS_JS_PSG_PROPERTY_EX(VALUE, VALUE) 在这种情况下,它会尝试生成名称为 Get"Version"Get"kProp" 的函数。 这应该只发生在#VALUE,而不是VALUE 我的错,我想说 Version 或 kProp 的内容在那里。容器宏会将参数替换为它们的内容并将它们传递给内部宏(如果它们是字符串,则作为字符串,如果它们是具有 1 作为值的 int,则作为“1”)。 #define kProp 1。它已经过预处理,因此不会使用名称kProp,而是使用值1 【参考方案1】:

诀窍是 - 如果您不想将名称扩展为宏,则必须立即将其传递给 ## 运算符 - 但连接的结果必须是有效的标记。像这样的:

#include <iostream>

#define CLASS_JS_PSG_PROPERTY_EX_HELPER(GetName) \
static bool GetName()  return true; 


#define CLASS_JS_PSG_PROPERTY_EX(PROPERTY, VALUE) \
CLASS_JS_PSG_PROPERTY_EX_HELPER(Get##PROPERTY)

#define CLASS_JS_PSG_PROPERTY(VALUE) \
CLASS_JS_PSG_PROPERTY_EX_HELPER(Get##VALUE)


#define kProp 1

CLASS_JS_PSG_PROPERTY_EX(Version, kProp)

CLASS_JS_PSG_PROPERTY(kProp)

int main() 
    std::cout << GetVersion() + GetkProp();

适用于 gcc 和 MSVC

您的原始代码似乎与 MSVC 一起工作的原因是因为 MSVC 预处理器是出了名的不合格 - 它对字符流(错误)而不是令牌流(正确)进行操作。在CLASS_JS_PSG_PROPERTY_EX(##VALUE, VALUE) 中,## 不是您所建议的一元运算符 - 它是将(VALUE 粘合到单个标记(VALUE 中的二元运算符。这不是一个有效的预处理令牌,所以程序格式错误,这就是 GCC 抱怨的地方。但是 MSVC 预处理器后来将这个无意义的标记分解成碎片(符合标准的预处理器永远不会这样做)。

【讨论】:

以上是关于gcc C++ 14 与 msvc++ 2015 中的级联宏的主要内容,如果未能解决你的问题,请参考以下文章

GCC默认导出所有符号与MSVC默认不导出任何东西之间的设计原理是啥?

C++ 在 GCC 上使用已删除的函数,但在 MSVC 上没有

gcc、clang 和 msvc 的 C++ 自动矢量化要求

g++ 与 MSVC 中 C++ 引号的含义

我们可以将 c++ 标准编译与 MSVC 混合使用吗?

Visual C++ 和 gcc 一样强大吗?