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)
这应该定义名为 GetVersion
和 GetkProp
的方法。
现在,这在 gcc C++14(实际上是 TDM-GCC-64)下会出现以下错误:
pasting "(" and "kProp" does not give a valid preprocessing token
应该如何编写才能在gcc C++14和msvc 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 上没有