C++17中constexpr函数内存储结果为constexpr变量报错的解决方案咨询
解决方案
C++17中无法直接在constexpr函数内部,将依赖函数参数的表达式结果声明为constexpr变量。不过可以通过以下方式实现类似的编译期检查需求:
1. 重载函数区分编译期与运行期调用
针对字符串字面量(编译期常量)和运行期字符串分别实现重载:
#include <string_view> #include <stdexcept> constexpr int f(std::string_view s) { return 1; } // 编译期调用版本:仅接收字符串字面量 template <std::size_t N> constexpr int g(const char (&s)[N]) { constexpr int res = f(std::string_view(s, N-1)); static_assert(res < 4, "invalid string s"); return res; } // 运行期调用版本:处理动态字符串 int g(std::string_view s) { int res = f(s); if (res >= 4) { throw std::invalid_argument("invalid string s"); } return res; } int main() { constexpr int i = f("hello"); constexpr int j = g("hello"); // 触发编译期检查 // int k = g(std::string_view("test")); // 触发运行期检查 return 0; }
这种方式既满足编译期static_assert的清晰报错需求,也能处理运行期的输入校验。
2. 模板元编程模拟字符串模板参数(仅支持字面量)
C++17不支持直接将std::string_view作为模板参数,但可以将字符串字面量转换为字符参数包,实现纯编译期的处理:
#include <string_view> #include <utility> template <char... Chars> constexpr int f() { return 1; } template <char... Chars> constexpr int g() { constexpr int res = f<Chars...>(); static_assert(res < 4, "invalid string s"); return res; } // 辅助模板:将字符串字面量转为字符参数包 template <std::size_t N, std::size_t... I> constexpr auto make_g(const char (&s)[N], std::index_sequence<I...>) { return g<s[I]...>(); } template <std::size_t N> constexpr auto g(const char (&s)[N]) { return make_g(s, std::make_index_sequence<N-1>()); } int main() { constexpr int i = g("hello"); // 编译期检查生效 return 0; }
该方案仅支持字符串字面量,无法处理运行期生成的字符串,但能完全满足编译期场景的报错需求。
3. 升级到C++20简化实现
如果可以升级到C++20,可利用std::is_constant_evaluated()在单个函数内区分编译期和运行期逻辑:
#include <string_view> #include <type_traits> #include <stdexcept> constexpr int f(std::string_view s) { return 1; } constexpr int g(std::string_view s) { int res = f(s); if (std::is_constant_evaluated()) { static_assert(res < 4, "invalid string s"); } else { if (res >= 4) { throw std::invalid_argument("invalid string s"); } } return res; } int main() { constexpr int i = f("hello"); constexpr int j = g("hello"); // 编译期检查 // int k = g(std::string_view("test")); // 运行期检查 return 0; }
内容的提问来源于stack exchange,提问作者francesco
相关产品推荐
相关产品推荐

