简体   繁体   English

使用 constexpr 替换 #define 和 #ifdef 进行条件编译

[英]Using constexpr to replace #define and #ifdef for conditional compilation

I am trying to replace the preprocessor #define and #if/#ifdef's that I am using to control conditional compilation with constexpr variables and ifs.我试图用 constexpr 变量和 ifs 替换我用来控制条件编译的预处理器 #define 和 #if/#ifdef。

Is it possible to declare constexpr variables such that they reproduce the #defines in that they don't allocate runtime storage, and that taking the address of one leads to a compile time error?是否可以声明 constexpr 变量,以便它们重现 #defines,因为它们不分配运行时存储空间,并且采用 1 的地址会导致编译时错误?

Edited to add code example.编辑以添加代码示例。

So in the headers I want to have something like所以在标题中我想有类似的东西

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

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

While in the code I want在我想要的代码中

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.

Then aim is then to change the definition of BuildPlatform on Line A, such that Line B is evaluated at compile time (and the else clause gets discarded/not compiled) and lines C and D (and anything that does the same thing, or relies on runtime storage for BuildPlatform) generates a compiler error.然后目标是更改 A 行上 BuildPlatform 的定义,以便在编译时评估 B 行(并且 else 子句被丢弃/未编译)和 C 行和 D 行(以及执行相同操作或依赖的任何内容)在 BuildPlatform 的运行时存储上)生成编译器错误。

Is such a construct possible in C++17?在 C++17 中可以使用这样的构造吗?

It is partially possible:部分可能:

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

but as template <typename T> void foo() {static_assert(false);} is ill formed, code of all branches should have some kind of validity.但是由于template <typename T> 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
    }
}

Maybe you can use this.也许你可以使用这个。

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)
{   
}

For flags and integers, enum values work.对于标志和整数,枚举值有效。

For floating point values, there is no constexpr way that guarantees no ODR usage.对于浮点值,没有 constexpr 方法可以保证不使用 ODR。 ODR usage tends to cause storage to be created for the constant. ODR 的使用往往会导致为常量创建存储。

You could use a constexpr function that returns a floating point value, but the function could easily take storage.您可以使用返回浮点值的 constexpr 函数,但该函数很容易占用存储空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM