必须将函数声明为constexpr或consteval,因std::is_constant_evaluated()仅在二者体内合法;consteval中它恒返回true;需用普通if而非if constexpr来分支,且编译期分支须纯constexpr操作。

你想让同一个函数在编译期走轻量路径、运行时走完整逻辑,又不希望编译器因分支污染而拒绝 constexpr 上下文——这需要精确控制求值时机与路径合法性。
确认函数必须声明为 constexpr 或 consteval
std::is_constant_evaluated() 只能在 constexpr 或 consteval 函数体内调用;普通函数中调用会直接编译失败,GCC/Clang 报错:call to non-constexpr function。
即使函数体只有一行 return std::is_constant_evaluated();,也必须加 constexpr 前缀。
consteval 函数内调用它时,【std::is_constant_evaluated() 恒返回 true】,因为 consteval 强制全程常量求值,不存在运行时退化可能。
立即学习“C++免费学习笔记(深入)”;
避免在 if 分支中混写非法操作
方法一:用 if constexpr 替代 if(仅当条件本身是编译期常量)
if constexpr (std::is_constant_evaluated()) 是错误写法——std::is_constant_evaluated() 返回的是运行时可变 bool,不是编译期常量表达式,不能用于 if constexpr。
方法二:严格隔离两分支语义
编译期分支里禁止出现 std::strlen、new、std::cout、非常量全局变量访问、非 constexpr 成员函数调用;哪怕该分支在运行时永远不会执行,只要存在,整个函数就无法通过 static_assert 或 NTTP 校验。
运行时分支可自由使用标准库设施,但它的存在本身会拖累编译期可用性——只要它含一行 std::printf,static_assert(f()) 就会失败。
拆分逻辑为独立辅助函数
第一步:编写纯 constexpr 版本,仅含字面量、循环、指针算术等安全操作
constexpr size_t literal_strlen(const char* s) { const char* p = s; while (*p) ++p; return p - s; }
第二步:编写运行时版本,可调用 std::strlen、malloc、系统 API 等
size_t runtime_strlen(const char* s) { return std::strlen(s); }
第三步:主函数仅做跳转,且自身声明为 constexpr
constexpr size_t safe_strlen(const char* s) { return std::is_constant_evaluated() ? literal_strlen(s) : runtime_strlen(s); }
注意:literal_strlen 必须能被常量求值上下文完整实例化;若传入的 s 是运行时指针(如局部数组名),则 literal_strlen 仍可能因越界访问或未定义行为导致编译失败。
强制调用点进入常量求值路径
static_assert(my_func("test") == 4); —— 断言成功即证明该次调用走编译期分支
constinit constexpr auto result = my_func("hello"); —— constinit 强制初始化发生在静态存储期,触发常量求值
template
若调用点是 int x = my_func(ptr);(ptr 为运行时变量),【std::is_constant_evaluated() 必然返回 false】,此时不会报错,但你期待的编译期优化完全不会发生。



















