【问题标题】:Defining symbolic string constants which have the same name and value定义具有相同名称和值的符号字符串常量
【发布时间】:2013-04-24 15:35:24
【问题描述】:

我有一些字符串我希望能够以符号方式使用,即好像我声明了一个宏

#define kBlahProperty "kBlahProperty"
#define kFooProperty "kFooProperty"

我不能使用枚举的原因有很多(有关更多上下文,请参阅previous question),例如在调试器中获取有用的信息、以可读格式序列化数据以及处理以不同方式定义的属性集源文件。

典型用法:

setProperty(kBlahProperty, 6);
if (otherProperty==kBlahProperty) { doStuff(); }
std::cout << "property type: " << kBlahProperty;  // outputs "kBlahProperty" rather than an enum

这些属性可能有很多,为了便于定义,我希望能够像这样声明它们,只在一个地方:

DEFINE_PROPERTY(kBlahProperty)
DEFINE_PROPERTY(kFooProperty)

但是,我找不到定义宏的方法,该宏本身会扩展为#define(我尝试了几个使用 '#' 和 '##' 运算符的示例,但要粘贴 ' #define' 是问题)。

另一种方法是将要扩展的宏定义为char*

#define DEFINE_PROPERTY(propName) const char8* propName=#propName

但这有一个问题,即它在每个编译单元中都被定义,因此出现链接器错误。如果我将其更改为使用extern,那么我无法将其定义为使用字符串本身——它必须放在 .cpp 文件中,所以现在我需要在标题中声明所有这些属性并再次定义它们在 cpp 文件中,因此您在两个地方都有一个列表。

那么有没有一种定义这些字符串的好方法,这样你就可以只声明它们一次?我可以使用 boost 预处理器,但只能使用 C++-0x 的一小部分(所以in-class constant initialisers 已经出局了)。

【问题讨论】:

  • 既然您使用的是 C++,为什么不使用std::string 处理字符串呢?如果你使用指针(或数组)在比较中错误地切换了操作数的顺序,则无法进行比较之类的事情。
  • 只是 FWIW,扩展为宏的宏无论如何都不会对您有任何好处:“生成的完全由宏替换的预处理令牌序列不会作为预处理指令处理,即使它类似于一个。 ..”
  • 简单(如果丑陋)方式 - 仅在未定义另一个符号时定义宏以包含 extern,并在包含标头之前在一个编译单元中定义该符号
  • @JoachimPileborg:不使用 std::string 的两个原因 - (1) 它仍然需要单独的声明和定义,就像 char* 所做的那样,以及 (2) 它必须是静态的常量,并且会冒着初始化问题的静态顺序的风险(即不能保证它会在其他可能引用它的东西之前构建)
  • @JerryCoffin:我怀疑可能是这样

标签: c++ c-preprocessor


【解决方案1】:

简单(如果丑陋)方式 - 仅在未定义另一个符号时定义宏以包含 extern,并在包含标头之前在一个编译单元中定义该符号

举个例子(为了清楚起见,包括省略的守卫)

#ifdef IN_CPP
#define DEFINE_PROPERTY(propName) const char8* propName=#propName;
#else
#define DEFINE_PROPERTY(propName) extern const char8* propName;
#endif

在一个编译单元中:

#define IN_CPP 1
#include "header.h"

在剩余的编译单元中:

#include "header.h"

【讨论】:

  • 我建议对此进行修改:使声明的对象保持不变。 ATM 它只是一个指向常量 char8 的非常量指针。使其成为 const 使链接成为内部链接,就像静态一样。使用不错的编译器和字符串池,您甚至不会浪费任何内存。
  • 初始化器是否也在extern上?只是好奇。
【解决方案2】:

您可以将宏定义为 have 和 #ifdef,使其具有两条路径 - if 和 else。然后在标题中它只是声明你的propName。然后在您的 .cpp 文件中,在包含标头之前定义一个预处理器变量。该定义将使您的宏 define 成为 propName。

【讨论】:

  • 这和上面的@antlersoft 的建议一样吗?
  • 另外,如果有很多这些属性,请考虑使用 const char[] 而不是 const char *。后者使用额外的空间来存储指针,前者没有。
  • 我用实际代码输入了这个来回答这个问题,但这可能就足够了,所以我不会打扰。这并不少见。 Microsoft 使用其 INITGUID 机制来声明和定义通用应用程序 GUID。
猜你喜欢
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 2021-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
相关资源
最近更新 更多