如何编写仅接受constexpr实参的constexpr函数?
如何编写仅接受constexpr实参的constexpr函数?
你遇到的这个问题,其实是C++里constexpr函数的一个典型痛点——普通的constexpr函数,哪怕你传的实参是constexpr的,函数里的参数本身也不会被当作编译期常量来用。这是因为constexpr函数允许在运行时调用,编译器得保留这种可能性,所以不会默认把参数视为编译期可用的。
不过在C++20里,有个完美的解决方案:consteval立即函数。
consteval是C++20新增的特性,它强制函数必须在编译期完成求值,完全禁止运行时调用。这意味着所有传入的实参必须是编译期常量,而且在函数内部,你可以放心地把参数当作constexpr来使用——比如用来指定std::array的大小,这正是你需要的场景。
针对你的代码,直接改造一下就能用:
#include <array> #include <string_view> constexpr std::array easy{'h', 'e', 'l', 'l', 'o'}; constexpr struct Hard { constexpr Hard(int n) : size_(n) {} size_t size_; constexpr size_t size() const { return size_; } } hard(10); constexpr std::string_view nope{"hello"}; // 用consteval替代原来的constexpr模板函数 consteval auto f(auto s) { return std::array<char, s.size()>(); } auto arr_easy = f(easy); // 完全正常编译 auto arr_hard = f(hard); // 没问题!hard是constexpr,consteval确保s在编译期可用 auto arr_nope = f(nope); // 也能正常工作!nope的size()会被编译期计算
为什么这个方案能解决你的所有问题?
- consteval函数的调用必须是编译期常量表达式,所以编译器会直接拒绝任何非constexpr实参的调用,完美实现“只接受constexpr实参”的需求。
- 在函数内部,参数
s会被当作编译期常量处理,所以s.size()可以安全地用作std::array的模板参数(毕竟模板参数要求必须是编译期常量)。 - 对比你之前尝试的非类型模板参数方案,consteval完全没有类型限制——不管是
std::array、你自定义的Hard,还是std::string_view,只要实参是constexpr的,就能正常传递和使用。
如果你的项目还不能升级到C++20,那情况会麻烦一些:
- 对于像
std::array、自定义Hard这类可以作为非类型模板参数的类型,你可以继续用模板方案; - 对于
std::string_view这类不支持非类型参数的类型,可能只能单独处理(比如手动指定大小),或者用宏来强制编译期上下文调用,但这些方案都远不如consteleg优雅。
所以如果编译器支持C++20,consteval绝对是最优解,完全匹配你的需求。
内容来源于stack exchange
相关产品推荐
相关产品推荐

