类模板能否从花括号初始化列表的大小推导size_t模板参数?
类模板能否从花括号初始化列表的大小推导size_t模板参数?
当然可以!而且还能顺便解决你提到的几个小痛点——减少嵌套括号、禁止N大于初始化列表长度的情况,我来一步步给你捋清楚怎么实现:
首先,咱们先解决核心问题:让编译器自动推导size_t N参数,同时简化初始化时的括号层数。原来的构造函数用了std::array作为参数,这就导致编译器得先知道N才能实例化std::array,自然没法反向从初始化列表推导N。咱们换个思路,用数组引用作为构造函数参数,再配合C++17的类模板实参推导(CTAD)和推导指引,就能完美解决:
#include <array> #include <utility> #include <algorithm> template <typename Key, typename Value, size_t N> class CustomMapStub { public: // 构造函数1:接受数组引用,直接用std::to_array初始化内部array(C++20及以上支持) CustomMapStub(const std::pair<Key, Value>(&init)[N]) : map_(std::to_array(init)) {} // 构造函数2:如果用户显式指定了N,强制检查初始化列表大小必须匹配 template <size_t M> CustomMapStub(const std::pair<Key, Value>(&init)[M]) { static_assert(M == N, "初始化列表的大小必须和模板参数N完全匹配!"); std::copy(std::begin(init), std::end(init), map_.begin()); } private: std::array<std::pair<Key, Value>, N> map_ = {}; }; // 推导指引:告诉编译器从初始化数组推导Key、Value和N(C++17及以上支持) template <typename Key, typename Value, size_t N> CustomMapStub(const std::pair<Key, Value>(&)[N]) -> CustomMapStub<Key, Value, N>;
现在咱们来看看怎么用这个修改后的类:
int main() { // 情况1:完全不用指定任何模板参数!编译器自动推导所有类型和N=3 CustomMapStub m1 = {{ {1, 1.0}, {2, 2.0}, {3, 3.0} }}; // 情况2:如果有人硬要指定N但大小不匹配,直接编译报错 // CustomMapStub<int, double, 4> m2 = {{ {1,1.0}, {2,2.0}, {3,3.0} }}; // 上面这行会触发static_assert的错误提示,完美符合你“不想让这种情况通过”的需求 // 情况3:初始化语法和std::map几乎一致,只需要一层外层括号包着键值对 CustomMapStub m3 = { {1, 1.0}, {2, 2.0}, {3, 3.0} }; // (注:有些编译器可能允许省略最外层的括号,不过加一层更保险,写法也更清晰) }
给你拆解下关键细节:
- 推导指引是C++17新增的特性,它能告诉编译器“当用户用某个类型的参数构造CustomMapStub时,应该推导成对应的模板参数”,这里就是从初始化数组的大小推导N。
- 构造函数里的
static_assert是核心,它强制要求显式指定的N必须和初始化列表的大小完全一致,直接把你说的“N大于初始化列表大小”的情况扼杀在编译阶段。 - 用
std::to_array可以直接把数组转成std::array,代码更简洁;如果用的是C++17,你可以换成std::copy手动拷贝元素。
如果你的项目还在用C++17之前的版本,没法用推导指引,那可以用一个工厂函数来实现推导:
template <typename Key, typename Value, size_t N> CustomMapStub<Key, Value, N> make_custom_map_stub(const std::pair<Key, Value>(&init)[N]) { return CustomMapStub<Key, Value, N>(init); } // 使用方式: auto m = make_custom_map_stub({{ {1,1.0}, {2,2.0}, {3,3.0} }});
这样也能实现自动推导,只是写法上多了个工厂函数的调用。
总结一下:
- 通过数组引用+推导指引,完美实现从初始化列表大小推导N的需求
- 用static_assert严格限制N和初始化列表大小一致,禁止不匹配的情况
- 初始化语法大幅简化,和std::map的写法几乎无差异
内容来源于stack exchange
相关产品推荐
相关产品推荐

