C++传入函数返回的constexpr值时static_assert编译失败问题
问题原因
constexpr函数只有传入的参数全部属于常量表达式时,才能在编译期求值得到常量结果,否则会退化为普通的运行期函数。- 函数模板
make_string的形参s是数组引用,即使你传入的实参是字符串字面值"abc",在make_string的函数体内部,s的地址属于编译期无法确定的量(字符串字面值的最终地址要到链接期才能确定),因此访问s[i]的操作无法在编译期执行,has_char_a(s)无法得到编译期常量,自然不满足static_assert要求操作数为常量的规则。 - 你直接在
test里调用has_char_a("abc")可以正常运行,是因为这个调用是运行期执行,没有要求编译期求值。
修复方案
方案1:C++20 字符串字面量模板参数(推荐)
C++20支持将字符串字面量作为模板非类型参数,可直接在编译期获取完整字符串内容:
#include <algorithm> #include <string> #include <iostream> using namespace std; template<size_t N> struct StringLiteral { constexpr StringLiteral(const char (&str)[N]) { std::copy_n(str, N, value); } char value[N]; }; template<StringLiteral Str> constexpr bool has_char_a() { for (size_t i = 0; i < sizeof(Str.value); i++) { if (Str.value[i] == 'a') return true; } return false; } template<StringLiteral Str> std::string make_string() { static_assert(has_char_a<Str>(), "error"); return std::string{ Str.value, sizeof(Str.value) - 1 }; } void test() { cout << has_char_a<"abc">() << endl; cout << make_string<"abc">() << endl; }
注:C20之前
std::string的构造函数不是constexpr,所以make_string不需要加constexpr修饰,C20及以上可按需添加。
方案2:调用侧预编译期求值(兼容低版本C++)
将判断逻辑移到函数调用侧,用constexpr变量提前接住编译期结果,再传入模板:
#include <string> #include <iostream> using namespace std; template<int N> constexpr bool has_char_a(const char(&s)[N]) { for (size_t i = 0; i < N; i++) { if (s[i] == 'a') return true; } return false; } template<int N, bool HasA> std::string make_string(const char(&s)[N]) { static_assert(HasA, "error"); return std::string{ s, N - 1 }; } void test() { constexpr bool has_a = has_char_a("abc"); cout << has_a << endl; cout << make_string<3, has_a>("abc") << endl; }
内容的提问来源于stack exchange,提问作者Zhang
相关产品推荐
相关产品推荐

