C++ 绕过#定义';d宏?

C++ 绕过#定义';d宏?,c++,c,c-preprocessor,C++,C,C Preprocessor,假设你有宏 #define TOKEN1 <arbitrary sequence of characters> #定义令牌1 但是,假设在一些情况下,您真正指的是TOKEN1,而不是它的定义。是否有一种技巧允许预处理文件包含“TOKEN1”,而不定义TOKEN1,并且在定义后出现TOKEN1 背景: 我正在通过重新定义new来添加内存跟踪。但是,我遇到了一个问题,我在几个类中重载了操作符new,在所有这些地方取消new的定义,然后重新包含完成之后的神奇操作的标题,这是很尴尬的 一

假设你有宏

#define TOKEN1 <arbitrary sequence of characters>
#定义令牌1
但是,假设在一些情况下,您真正指的是TOKEN1,而不是它的定义。是否有一种技巧允许预处理文件包含“TOKEN1”,而不定义TOKEN1,并且在定义后出现TOKEN1

背景:


我正在通过重新定义
new
来添加内存跟踪。但是,我遇到了一个问题,我在几个类中重载了
操作符new
,在所有这些地方取消new的定义,然后重新包含完成之后的神奇操作的标题,这是很尴尬的

一般方法是将所有具有“请勿替换令牌1”要求的代码放在一个单独的源文件中,然后不将定义替换的头文件包含在该文件中

如果任意字符序列是单个标记(与编辑问题之前一样),则可以执行以下操作:

#define TOKEN2 TOKEN1
if (you_really_mean(TOKEN1)) {
    //...
}
#undef TOKEN2
#define TOKEN1 TOKEN2
#define TOKEN2 <arbitrary sequence formerly assigned to TOKEN1>
但是,这个解决方案是有限的,因为如果
TOKEN2
以前已经被重新定义为其他东西,您就会遇到问题

如果您完全控制定义的内容和未定义的内容,则可以执行以下操作:

#define TOKEN2 TOKEN1
if (you_really_mean(TOKEN1)) {
    //...
}
#undef TOKEN2
#define TOKEN1 TOKEN2
#define TOKEN2 <arbitrary sequence formerly assigned to TOKEN1>

对于处理重载
new
的特定问题,我发现重载
new
实现在很大程度上是相同的(因为它们通常只是锅炉板代码,将分配器更改为使用系统堆以外的东西)。如果您也是这样,您可以将重载定义放入无保护的头文件中。此头文件可以
#undef
定义
new
,然后在重载定义后重新定义它


然后,任何类都可以包含此头文件。

如果
作为宏调用有效(其形式为标识符或
id(args)
),则可以通过添加“reverse”宏临时绕过定义

我认为不存在真正任意序列的扩展令牌的解决方法。而且,这种解决方法实际上并不比
#undef TOKEN1
然后再次执行
#define
好多少,因为绕过代码仍然需要知道扩展。

如果您可以访问语言扩展,可以这样做(我认为MSVC也有类似的方法):

#define TOKEN1 123
#pragma push_macro("TOKEN1")
#undef TOKEN1
TOKEN1     // inserts TOKEN1 into the program text
#pragma pop_macro("TOKEN1")
TOKEN1     // inserts 123 into the program source text
它允许您独立于输入文本保存和恢复宏定义,仅用于此目的


不过,jxh的解决方案更干净;但从根本上说,你应该重新思考你试图让一个术语具有多重含义的原因。宏语言应该帮助您抽象单个统一程序的元素;不要在一个文件中创建两个相互竞争的战斗源。

如果您有权更改令牌1的定义,您可以:

#define TOKEN1() arbitrary stuff...

然后
TOKEN1
后面不跟
不进行扩展。即使后面有
您仍然可以通过写入
(TOKEN1)来抑制它)

没有办法,在编译之前,预处理器会盲目地替换文本,因此如果你不
#undef
它,你就不能要求编译器忽略预处理器。@vsoftco没有办法编写一个计算为TOKEN1的宏,而预处理器则不会计算它?好吧,我想你可以这样做
#定义TOKEN2 TOKEN1
,然后当您编写
TOKEN1
时,预处理器会将其替换为
TOKEN2
,然后将其替换为
TOKEN1
,此时它将停止替换…@T.C.:看起来您在我回答的同时发布了此评论。请注意,只要
TOKEN2
没有,它就可以工作已被重新定义为其他内容。因此,对于宏和实际语言标识符,使用不同命名约定是常见的编码约定。另一种方法是要求项目使用除
new
之外的某种机制来分配内存,该机制包含调试内容。然后,您可以尝试禁用e常规
分配器的用户。请参阅。