使用is_constant_evaluated统一constexpr函数行为遇编译错误咨询
std::is_constant_evaluated 导致的常量表达式编译错误分析
问题场景
使用GCC12.2编译器并开启-std=c++20编译选项编写代码,尝试通过std::is_constant_evaluated统一constexpr函数的行为,但调用LOGMSG(str1)时出现编译错误:
error: the value of ‘str1’ is not usable in a constant expression constexpr auto numArgs = count(FMT);
相关代码
#include <memory> #include <iostream> #include <string.h> template<size_t arrSize> void print() { std::cout << "Number of format characters: " << arrSize << "\n"; } constexpr size_t countFormat(const char* format) { if(format[0] == '\0') return 0; return (format[0] == '%' ? 1u : 0u) + countFormat(format + 1); } constexpr size_t count(const char* format) { return std::is_constant_evaluated() ? countFormat( format ) : 0; } #define LOGMSG(FMT) { constexpr auto numArgs = count(FMT); print<numArgs>(); } int main() { const auto str1 = "Test %d %s"; constexpr auto str2 = "Test %d %s"; LOGMSG(str1); LOGMSG(str2); LOGMSG("Test %d %s"); return 0; }
错误原因
核心矛盾:const与constexpr变量的本质区别
str1是**const修饰的自动存储期变量**,而非constexpr变量:
- 虽然
str1的值是字符串字面量,但它存储在栈上(自动存储期),其地址不属于常量表达式范畴。 - 当
LOGMSG(str1)展开后,constexpr auto numArgs = count(str1);要求count(str1)必须是常量表达式(因为numArgs是constexpr变量),此时整个count函数的调用处于常量求值上下文,std::is_constant_evaluated()会返回true,进而执行countFormat(str1)。 countFormat需要在常量求值中访问format指向的内容,但str1的地址不是常量表达式,无法在常量求值过程中被合法引用,因此触发编译错误。
对比成功案例的逻辑
str2是constexpr变量:其地址属于常量表达式,能在常量求值中被countFormat正常访问。- 直接传入字符串字面量:字符串字面量本身就是常量表达式,自然满足常量求值的要求。
关于std::is_constant_evaluated的误区
std::is_constant_evaluated()仅用于判断当前是否处于常量求值上下文,无法将非常量表达式的参数“转换”为常量表达式。只要count被用于初始化constexpr变量,就必须保证整个调用链都符合常量表达式的要求,而str1不满足这一前提。
内容的提问来源于stack exchange,提问作者bramasub
相关产品推荐
相关产品推荐

