除了使用 #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 bool
s。
如果您需要真正意义上的条件编译,并且可以使用 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
的更多信息:
在处理条件编译时,省略在编译时声明定义是很常见的,使它更类型安全的一个好技巧是使用枚举(布尔值也可以)以确保有效值在编译时定义。
示例
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();
}
我想使用条件编译来测试我的代码的不同属性;但是,我不想污染全局命名空间。如果有一种方法可以在不使用 #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 bool
s。
如果您需要真正意义上的条件编译,并且可以使用 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
的更多信息:
在处理条件编译时,省略在编译时声明定义是很常见的,使它更类型安全的一个好技巧是使用枚举(布尔值也可以)以确保有效值在编译时定义。
示例
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();
}