如何用相同构造参数初始化带模板参数的无默认构造std::array?
如何初始化元素无默认构造函数的std::array(模板大小未知)
你遇到的问题很典型:当std::array的元素类型没有默认构造函数,而数组大小又是模板参数时,直接初始化会因为无法默认构造元素而触发编译错误。要把mAs里的所有A对象都初始化为A{b,c},我们可以利用编译期索引序列来实现,下面是几种可行的方案:
方案一:C++14及以上(兼容性最好)
我们可以借助std::index_sequence和模板构造函数,在编译期展开初始化每个元素:
#include <array> #include <utility> // 引入std::index_sequence相关工具 struct A { A(int b, int c) : mb(b), mc(c) {} int mb; int mc; }; template <size_t NR_A> struct B { private: // 辅助构造函数:利用编译期索引序列展开初始化 template <size_t... Is> B(int b, int c, std::index_sequence<Is...>) : mAs{ (static_cast<void>(Is), A{b, c})... } {} public: B(int b, int c) : B(b, c, std::make_index_sequence<NR_A>{}) {} std::array<A, NR_A> mAs; }; // 测试代码 B<3> inst(1, 1);
原理说明
std::make_index_sequence<NR_A>会生成一个包含0,1,...,NR_A-1的编译期索引序列;- 初始化列表里的
(static_cast<void>(Is), A{b,c})利用逗号运算符忽略索引值,为每个位置构造一个A{b,c}; - 展开后相当于显式写出
A{b,c}, A{b,c}, ...(共NR_A次),完美绕过了std::array默认构造元素的需求。
方案二:C++20及以上(更简洁)
如果你能使用C++20,可以结合std::to_array和lambda表达式来实现:
#include <array> #include <utility> struct A { A(int b, int c) : mb(b), mc(c) {} int mb; int mc; }; template <size_t NR_A> struct B { B(int b, int c) : mAs(std::to_array<A>([b,c]<size_t... Is>(std::index_sequence<Is...>) { return std::array{A{b,c}...}; }(std::make_index_sequence<NR_A>{}))) {} std::array<A, NR_A> mAs; }; B<3> inst(1, 1);
为什么原代码会报错?
因为你自定义了A的构造函数,编译器不会再自动生成默认构造函数;而std::array的默认构造函数会尝试默认构造每个元素,这就导致std::array<A, 3UL>的默认构造函数被隐式删除,直接初始化自然会失败。我们的方案都是通过显式构造每个元素,避开了默认构造的要求。
内容的提问来源于stack exchange,提问作者Alex Darsonik
相关产品推荐
相关产品推荐

