使用constexpr函数结果作为模板参数编译报错,寻求解决方案
问题分析与解决方案
你的问题核心在于模板参数必须是编译期可确定的常量,但你在partition::operator()里使用的data.size()是一个运行时计算的值——虽然slice::size()是constexpr成员函数,但只有当调用它的slice对象本身是constexpr实例时,返回值才会被视为编译期常量。而当前代码里,operator()的参数const slice& data是运行时构造的对象,因此data.size()无法满足模板参数的编译期常量要求,导致报错。
问题拆解
key<std::size_t size>的模板参数size要求在编译阶段就确定具体值;- 你当前的
operator()接收slice引用,这个slice是从字符串字面量运行时构造而来(即便slice的构造函数是constexpr,但operator()本身不是constexpr,所以data并非编译期对象); - 因此
data.size()是运行时计算的结果,不符合模板参数的常量要求。
直接解决方案:让模板参数从编译期推导
最贴合你使用场景的修复方式,是修改partition::operator(),让它直接接收字符串字面量,这样编译器可以在编译期推导出字符串的长度,作为key的模板参数。修改后的完整代码如下:
#include <functional> #include <string_view> #include <array> class slice { public: template <std::size_t size> constexpr slice(char const (&data)[size]) noexcept : _size(size), _data(data) {} constexpr const char* data() const { return _data; } constexpr std::size_t size() const { return _size; } private: const std::size_t _size; const char* _data; }; template <std::size_t size> class key { public: constexpr key(std::size_t hash, const char* data) : _hash(hash), _data(data, data + size) {} private: std::size_t _hash; std::array<char, size> _data; }; class partition { public: partition(std::string_view name) : _hash(std::hash<std::string_view>{}(name)) {} // 修改为直接接收字符串字面量,编译期推导size template <std::size_t size> auto operator()(char const (&data)[size]) { return key<size>(_hash, data); } // 可选:额外重载支持constexpr的slice对象(需编译期调用) template <std::size_t size> constexpr auto operator()(const slice& data) requires (size == data.size()) { return key<size>(_hash, data.data()); } private: const std::size_t _hash; }; // 你的使用示例可以正常运行 int main() { partition partition1{ "partition 1" }; partition partition2{ "partition 2" }; auto key1 = partition1("key 1"); auto key2 = partition2("key 1"); }
其他可选思路
如果你确实需要通过slice作为中间层传递数据,那么需要确保slice对象是constexpr,同时partition::operator()也声明为constexpr,这样data.size()才能成为编译期常量:
// 必须在编译期构造partition和slice constexpr partition partition1{ "partition 1" }; constexpr slice s{ "key 1" }; constexpr auto key1 = partition1(s);
不过这种方式会限制使用场景,必须在编译期完成构造和调用,可能不符合你“便捷创建分区”的需求。
内容的提问来源于stack exchange,提问作者Martijn Otto
相关产品推荐
相关产品推荐

