FMa*_*iro 5 c++ constexpr c++17
给定一个 constexpr 函数,是否有办法在编译时调用该函数时创建编译时错误,并在运行时调用该函数时返回哨兵值?
不幸的是,我无法使用异常,因为它们在构建中被禁用。
这主要用于与枚举之间的转换以及与字符串之间的转换。如果开发人员输入了不正确的值,最好让构建失败,而不是希望他们在运行时看到错误,但由于我们可以从未知来源获取值,因此该值有可能无效,我们不这样做不想在运行时崩溃。
演示用例:
#include <fmt/core.h>
#include <iostream>
// from: https://stackoverflow.com/a/63529662/4461980
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
enum class MyEnum { A, B, C, END_OF_ENUM };
constexpr const char* ToString(MyEnum value) {
switch (value) {
case MyEnum::A: {
return "A";
}
case MyEnum::B: {
return "B";
}
case MyEnum::C: {
return "C";
}
case MyEnum::END_OF_ENUM:
default: {
if (is_constant_evaluated()) {
// compile time error?
return "test";
} else {
return "UNKNOWN";
}
}
}
// unreachable?
return "";
}
int main(int argc, char** argv) {
// strcitly-speaking not UB since 5 is 0b101 in binary which does not use more bits than the
// highest item which would have value 4 which would be 0b100
// for demo purposes only, don't scream at me
constexpr auto stringified = ToString(static_cast<MyEnum>(5));
fmt::print("{}\n", stringified); // prints "test"
fmt::print("{}\n", ToString(static_cast<MyEnum>(5))); // prints "UNKNOWN"
}
Run Code Online (Sandbox Code Playgroud)
我会考虑的一种选择是这样写
constexpr const char* ToString(MyEnum value) {
switch (value) {
case MyEnum::A: {
return "A";
}
case MyEnum::B: {
return "B";
}
case MyEnum::C: {
return "C";
}
case MyEnum::END_OF_ENUM:
default: ;
}
if(!is_constant_evaluated()) {
assert(0 && "Converting value out of range"!);
return "";
}
}
Run Code Online (Sandbox Code Playgroud)
常量求值的一个控制原则是,当对表达式进行常量求值时,核心语言中不允许出现未定义的行为。从具有非 void 返回类型的函数末尾流出的就是编译器将捕获并报告的 UB 实例之一。
然后,用户将被引导至函数的末尾,希望断言消息能够为他们提供线索。在常规运行时评估中,我们得到通常的assert逻辑 - 在没有异常的情况下,如您所指定的。
| 归档时间: |
|
| 查看次数: |
206 次 |
| 最近记录: |