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

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

我想使用条件编译来测试我的代码的不同属性;但是,我不想污染全局命名空间。如果有一种方法可以在不使用 #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

当使用预处理器定义时,我们总是必须权衡我们正在污染 "global namespace"。

当然,它并不是真正的全局命名空间,而是它自己的命名空间:麻烦的是,由于它们的性质,这些宏名称实际上在 每个 范围内生效。

我们只接受这一点。


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

如果您需要真正意义上的条件编译,并且可以使用 if constexpr 在 non-preprocessor C++ 中进行拼写,那就更好了。

否则这就是我们必须处理的事情。我们至少尽量使用描述性名称,避免使用可能与 third-party header 冲突的通用术语。 If/when他们这样做,我们改变他们。


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

例如,OpenGL 渲染器实现与 DirectX 渲染器实现(这个例子只有在构建时在它们之间切换时才有效,就像使用宏一样!)。

如果您使用的是 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 的更多信息:

The year is 2017 - Is the preprocessor still needed in C++?

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

示例

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();
}