除了使用 #define 进行条件编译之外,还有其他选择吗?

Are there any options other than using #define for conditional compilation?

本文关键字:其他 选择 编译 #define 条件      更新时间:2023-10-16

我想使用条件编译来测试代码的不同属性;但是,我不想污染全局命名空间。有人会好心让我知道是否有办法在不使用#define的情况下使用条件编译吗?

我已经搜索了一个选项,但大多数其他帖子都提到了static const等在运行时选择不同代码的使用。但是,我想编译不同的代码。例如,代替:

#define A_HASH_DEFINE
...
#ifdef A_HASH_DEFINE
Some code
#elif ANOTHER_HASH_DEFINE
Some other code
#endif

我希望能够使用带有范围的东西,例如:

scope::A_SCOPED_HASH_DEFINE
...
#ifdef scope::A_SCOPED_HASH_DEFINE
Some code
#elif scope::ANOTHER_SCOPED_HASH_DEFINE
Some other code
#endif

如果您使用的是 C++17,则应使用if constexpr.

它本质上是一个if语句,其中分支是在编译时选择的,任何未采用的分支都会被丢弃。它比在整个代码中散布#ifdef更干净。

#ifdef _DEBUG
constexpr bool debug_mode = true;
#else
constexpr bool debug_mode = false;
#endif
if constexpr (debug_mode) {
//debug code
}

您可以在FooNathan的博客中阅读有关它如何替换#if … #else的更多信息:

今年是 2017 年 - C++ 中还需要预处理器吗?

使用预处理器定义时,我们始终必须处理污染"全局命名空间"的权衡。

当然,它不是真正的全局命名空间,但它是自己的命名空间:问题是,由于它们的性质,这些宏名称实际上在每个作用域中都有效。

我们只是接受这一点。


我们试图通过将它们保留在单独的翻译单元来限制它们。或者,如果它们需要在标头中,我们切换到const bools。

如果您需要真正意义上的条件编译,并且您可以使用if constexpr在非预处理器C++中拼写它,那就更好了。

否则,这只是我们必须处理的事情。我们至少尝试使用描述性名称,并避免使用可能与第三方标头冲突的常用术语。如果他们这样做,我们会改变他们。


如果您仍然发现宏污染太大,则可能是您的切换逻辑封装了太多代码。在这种情况下,您可以考虑将逻辑移动到构建系统中,并首先更改构建的源文件。

例如,OpenGL 渲染器实现与 DirectX 渲染器实现(该示例仅在构建时在它们之间切换时才有效,就像使用宏一样!

在处理条件编译时,省略在编译时声明定义是很常见的,使其更加类型安全的一个很好的技巧是使用枚举(布尔值也可以工作)来确保在编译时定义有效的值。

enum class SystemEnum { MAC, LINUX, WINDOWS };
const SystemEnum mySystem = SystemEnum::MY_SYSTEM;
void func() {
#if MY_SYSTEM == MAC
doMacStuff();
#elif MY_SYSTEM == LINUX
doLinuxStuff();
#elif MY_SYSTEM == WINDOWS
doWindowsStuff();
#else
#error "You must define MY_SYSTEM to compile this"
#endif
if constexpr (mySystem == SystemEnum::MAC)
doMacStuff();
else if constexpr (mySystem == SystemEnum::LINUX)
doLinuxStuff();
else if constexpr (mySystem == SystemEnum::WINDOWS)
doWindowsStuff();
else
doError();
}