【问题标题】:Are there any options other than using #define for conditional compilation?除了使用#define 进行条件编译之外,还有其他选择吗?
【发布时间】:2019-12-20 12:53:55
【问题描述】:

我想使用条件编译来测试我的代码的不同属性;但是,我不想污染全局命名空间。有人能告诉我是否有办法在不使用#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

【问题讨论】:

  • 预处理器在这方面是愚蠢的。没有作用域,只有更长的名称,例如:SCOPE_A_SCOPED_HASH_DEFINE
  • 范围是指名称空间吗?在命名空间内使用constexpr constexpr uint64_t HASH_DEFINE = 256;
  • @user4581301 我明白了。我想这就是我必须做的:/谢谢!
  • @ajax_velu 是的,我的意思是在命名空间内。 constexpr 是否适用于 #ifdef 预处理器命令?
  • 如果您正在查看许多非常不同或非常复杂的代码,请考虑将不同的代码放在单独的文件中,并让构建系统通过链接到正确的文件来处理它。

标签: c++ compilation c-preprocessor conditional-compilation


【解决方案1】:

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

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

#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++?

【讨论】:

  • 非常感谢!当我回到家时,我将阅读这篇文章。我相信,这解决了我大部分项目的问题。是否可以将它用于 C++ 11 及更高版本,而不仅仅是 C++17 及更高版本?
  • @AnilCelikMaral tbh,现在大多数编译器都能够删除基于常量表达式的代码,所以这里的 constexpr 只是对编译器的提示,它已经可以弄清楚。在此处查看这个愚蠢的示例:godbolt.org/z/4WIq_2 如果选项为 const,则该方法的代码将被完全删除。将其更改为 true,将提示编译器生成代码。
  • @robthebloke 不,不仅如此。未采用constexpr 分支内的代码可能是“无效的”,如果您只是依赖优化,则情况并非如此。两种不同的野兽。
【解决方案2】:

在使用预处理器定义时,我们总是不得不权衡我们正在污染“全局命名空间”。

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

我们只是接受。


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

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

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


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

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

【讨论】:

  • 我想我会更多地研究 constexpr。现在,我将让 Makefile 根据我想要的版本来处理构建不同的版本。非常感谢您的解释!
猜你喜欢
  • 2023-02-09
  • 1970-01-01
  • 2023-01-03
  • 2012-06-04
  • 2012-03-28
  • 2015-12-08
  • 1970-01-01
  • 1970-01-01
  • 2020-08-17
相关资源
最近更新 更多