如何实现constexpr函数编译时报错、运行时返回哨兵值(禁用异常)
编译时校验无效值、运行时返回哨兵值的constexpr实现
需求说明
实现一个constexpr函数,需满足以下逻辑:
- 当函数在编译时被调用且传入无效值时,直接触发编译错误,终止构建流程;
- 当函数在运行时被调用且传入无效值时,返回预设的哨兵值,避免程序崩溃;
- 构建环境禁用异常,无法依赖异常机制处理错误。
该功能主要用于枚举与字符串互转场景:
- 针对开发者手动输入的错误值,希望在编译阶段就暴露问题,无需等到运行时才发现;
- 针对来自外部未知来源的无效值,程序需保持健壮性,返回预设的哨兵值而非崩溃。
实现代码
#include <fmt/core.h> #include <iostream> // 兼容多版本C++的编译时判断工具函数 #if __cplusplus >= 202002L #include <type_traits> #endif constexpr bool is_constant_evaluated() { #if __cplusplus >= 202002L return std::is_constant_evaluated(); #elif defined(__GNUC__) // GCC和Clang均支持该内置函数 return __builtin_is_constant_evaluated(); #else // 若编译器不支持内置函数,默认返回true,确保编译时逻辑被执行 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()) { // 编译时触发错误:无效的枚举值 static_assert(false, "无效的MyEnum枚举值"); } // 运行时返回哨兵值 return "UNKNOWN"; } } } int main(int argc, char** argv) { // 编译时调用:传入无效值会触发编译错误,注释掉以下行可正常编译 // constexpr auto stringified = ToString(static_cast<MyEnum>(5)); // 运行时调用:传入无效值返回"UNKNOWN" fmt::print("{}\n", ToString(static_cast<MyEnum>(5))); }
关键实现细节
- 编译时判断:通过
is_constant_evaluated()函数区分编译时和运行时调用场景,兼容C++17及以上版本的主流编译器; - 编译时错误触发:在编译时分支中使用
static_assert(false, ...)直接终止编译,明确提示错误原因; - 运行时健壮性:运行时分支返回预设的哨兵值
"UNKNOWN",确保程序不会因无效输入崩溃; - 枚举覆盖:switch语句覆盖所有有效枚举值,默认分支统一处理无效情况。
内容的提问来源于stack exchange,提问作者Florian Humblot
相关产品推荐
相关产品推荐

