我能否重新定义C++宏然后再次定义它?

47
我在我的代码中同时使用JUCE库和一些Boost头文件。Juce将“T”定义为宏(呻吟),而Boost经常在其模板定义中使用“T”。结果是,如果你在Boost头文件之前包含了JUCE头文件,预处理器会在Boost代码中扩展JUCE宏,然后编译器就会陷入无望的困境。
大多数情况下,保持正确的包含顺序并不难,但当你有一个JUCE类包含其他一些类,并且链上某个文件包含了Boost时,如果任何一个文件需要JUCE包含,你就会遇到麻烦。
我最初修复这个问题的希望是:
#undef T

在任何使用Boost之前,必须先定义“T”。但问题是,如果我不重新定义它,那么其他代码会混淆“T”未声明。

然后我想也许我可以使用一些循环的#define技巧,像这样:

// some includes up here
#define ___T___ T
#undef T
// include boost headers here
#define T ___T___
#undef ___T___

虽然很丑,但我认为它可能会起作用。

可惜并没有。在使用“T”作为宏时出现了错误

'___T___' was not declared in this scope.

有没有一种方法可以使这两个库可靠地一起工作?

为什么你要将__T__定义为T,然后立即取消定义T(在下面反之亦然)? - Jim Buck
我猜我可以通过查找原始定义并重新定义来解决问题,但我更希望有一些更通用和可靠的东西。 - Aftermathew
Jim,我不确定格式是否使你的问题更难理解,但我认为我的问题很清楚?你能否重新表述一下你的问题? - Aftermathew
我认为这是不可能的。也许可以创建一个包装头文件,取消定义 T 并使用不同名称定义宏。 - UncleBens
3个回答

73
正如greyfade所指出的,你的___T___技巧无法奏效,因为预处理器是一个相当简单的程序。另一种方法是使用#pragma指令:
 // juice includes here
 #pragma push_macro("T")
 #undef T
 // include boost headers here
 #pragma pop_macro("T")

这应该适用于MSVC++,而GCC已经添加了对pop_macropush_macro的支持以与之兼容。从技术上讲,这取决于具体实现,但我认为没有标准的临时抑制定义的方法。


六年过去了,这个技巧仍然很酷!我使用这种技术使Win32 DLL能够消耗自己的一个入口点,而无需创建模块定义文件! - David A. Gray

11

您能够在另一个包含文件中包装有问题的库并捕获 #define T 吗?

例如:

JUICE_wrapper.h:     
#include "juice.h"
#undef T

main.cpp:    
#include "JUICE_wrapper.h"    
#include "boost.h"

 rest of code....

1
我正想建议在每个 #include "juice.h" 后面添加一个 #undef T。这里的想法相同但更加简洁。 - deft_code
MGB,我最终做了你建议的事情,但感觉Peter更准确地回答了问题。非常感谢你的建议。 - Aftermathew
我一直在寻找push/pop宏以确切地了解它的作用,但是我找不到它!在末尾加上“_macro”太傻了。 - Martin Beckett

5
我曾经认为我可以使用一些循环 #define 的技巧来解决这个问题:
C 预处理器并不是这样工作的。预处理器符号的定义并不像定义一个函数那样给符号赋予含义。
你可以把预处理器看作是一个文本替换引擎。当一个符号被定义时,它被视为纯文本替换,直到文件结束或者它被取消定义。它的值没有存储在任何地方,因此不能被复制。因此,在您使用 #undef 取消定义之后恢复 T 的定义的唯一方法是在代码中完全重新生成其值,并使用新的 #define
您所能做的最好的办法就是简单地不使用 Boost 或请求 JUCE 的开发人员不要将 T 用作宏。(或者最坏的情况下,通过更改宏的名称自行修复它。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接