【问题标题】:Using constexpr to replace #define and #ifdef for conditional compilation使用 constexpr 替换 #define 和 #ifdef 进行条件编译
【发布时间】:2018-09-20 22:03:13
【问题描述】:

我正在尝试用 constexpr 变量和 ifs 替换我用来控制条件编译的预处理器 #define 和 #if/#ifdef。

是否可以声明 constexpr 变量,以便它们重现 #defines,因为它们不分配运行时存储,并且获取 one 的地址会导致编译时错误?

编辑添加代码示例。

所以在标题中我想要类似的东西

namespace ExampleNamespace
{
  enum class Platform : int {Darwin, Linux, Windows};

  constexpr Platform BuildPlatform = Platform::Darwin;  // Line A.
};

在我想要的代码中

if constexpr (Platform::Darwin == BuildPlatform)        // Line B.
  {
    cout << "Platform is Darwin" << endl;
  }
else
  {
    cout << "Platform is not Darwin" << endl;
  };

const Platform *const PlatformAddress = &BuildPlatform; // Line C.
const Platform &BuildPlatform2 = BuildPlatform;         // Line D.

然后目标是更改 A 行上 BuildPlatform 的定义,以便在编译时评估 B 行(并且 else 子句被丢弃/未编译)以及 C 和 D 行(以及任何做同样事情的东西,或依赖于 BuildPlatform 的运行时存储)会生成编译器错误。

这样的构造在 C++17 中是否可行?

【问题讨论】:

  • 给出代码示例,原样,太宽泛了。
  • This 可能有帮助
  • 地址比较容易被屏蔽(除非使用std::addressof),但引用比较困难,也会导致ODR存在。您的变量是整数常量还是浮点值或究竟是什么?
  • constexpr 不能帮助你有条件地存在变量,例如我不想有 int x;如果我在 Windows 上......而预处理器可以。
  • @Jarod42 添加了代码示例。

标签: c++ constants c++17 constexpr


【解决方案1】:

部分可能:

if constexpr (Platform::Darwin == BuildPlatform) {        // Line B.
    std::cout << "Platform is Darwin" << std::endl;
} else {
    std::cout << "Platform is not Darwin" << std::endl;
}

但由于template &lt;typename T&gt; void foo() {static_assert(false);} 格式不正确, 所有分支的代码都应该具有某种有效性。

#ifdef (DarwinPlatform) // constexpr cannot be used here, you have to 
                        //rely on MACRO here
# include <darwin.h>     // Some OS specific header
#endif

void foo()
{
    if constexpr (Platform::Darwin == BuildPlatform) {
        DarwinMethod(); // Won't compile on other platforms as
                        // the method doesn't exist.
        // you should make the block template with template dependent code
        // to allow code to compile.
        // as http://coliru.stacked-crooked.com/a/c695575e4dcdecee
    }
}

【讨论】:

    【解决方案2】:

    也许你可以用这个。

    enum class Platform { Darwin, Linux, Windows };
    
    #ifdef __darwin__
    constexpr Platform  BuildPlatform = Platform::Darwin;
    #elif __linux__
    constexpr Platform  BuildPlatform = Platform::Linux;
    #elif __WIN32
    constexpr Platform  BuildPlatform = Platform::Windows;
    #endif
    
    // your code then uses it like this
    
    if constexpr (BuildPlatform == Platform::Darwin) 
    {         
    }
    else if constexpr (BuildPlatform == Platform::Linux)
    {
    }
    else if constexpr (BuildPlatform == Platform::Windows)
    {   
    }
    

    【讨论】:

      【解决方案3】:

      对于标志和整数,枚举值有效。

      对于浮点值,没有 constexpr 方法可以保证不使用 ODR。 ODR 的使用往往会导致为常量创建存储空间。

      您可以使用返回浮点值的 constexpr 函数,但该函数很容易占用存储空间。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      • 1970-01-01
      • 2011-03-27
      • 2011-07-31
      • 2019-01-30
      • 2019-12-20
      • 2021-10-04
      相关资源
      最近更新 更多