使用constexpr代替#define和#ifdef进行条件编译
Using constexpr to replace #define and #ifdef for conditional compilation
我正在尝试用 constexpr 变量和 ifs 替换我用来控制条件编译的预处理器 #define 和 #if/#ifdef。
是否可以声明 constexpr 变量,使它们重现 #defines,因为它们不分配运行时存储,并且取一个地址会导致编译时错误?
编辑以添加代码示例。
所以在 headers 我想有类似
的东西
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 子句得到 discarded/not 编译)和 C 行和 D 行(以及任何做同样的事情,或者依赖于 BuildPlatform 的运行时存储)生成编译器错误。
这样的构造在 C++17 中可行吗?
部分可能:
if constexpr (Platform::Darwin == BuildPlatform) { // Line B.
std::cout << "Platform is Darwin" << std::endl;
} else {
std::cout << "Platform is not Darwin" << std::endl;
}
但由于 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
}
}
对于标志和整数,枚举值有效。
对于浮点值,没有保证不使用 ODR 的 constexpr 方法。 ODR 使用往往会导致为常量创建存储。
您可以使用一个 returns 浮点值的 constexpr 函数,但该函数很容易占用存储空间。
也许你可以用这个。
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)
{
}
我正在尝试用 constexpr 变量和 ifs 替换我用来控制条件编译的预处理器 #define 和 #if/#ifdef。
是否可以声明 constexpr 变量,使它们重现 #defines,因为它们不分配运行时存储,并且取一个地址会导致编译时错误?
编辑以添加代码示例。
所以在 headers 我想有类似
的东西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 子句得到 discarded/not 编译)和 C 行和 D 行(以及任何做同样的事情,或者依赖于 BuildPlatform 的运行时存储)生成编译器错误。
这样的构造在 C++17 中可行吗?
部分可能:
if constexpr (Platform::Darwin == BuildPlatform) { // Line B.
std::cout << "Platform is Darwin" << std::endl;
} else {
std::cout << "Platform is not Darwin" << std::endl;
}
但由于 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
}
}
对于标志和整数,枚举值有效。
对于浮点值,没有保证不使用 ODR 的 constexpr 方法。 ODR 使用往往会导致为常量创建存储。
您可以使用一个 returns 浮点值的 constexpr 函数,但该函数很容易占用存储空间。
也许你可以用这个。
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)
{
}