如何使用参数包构造元素无默认构造函数的定长std::array
实现方案
完全可以实现,核心思路是借助编译期整数序列std::index_sequence生成N个重复的初始化构造调用,不同C++标准的实现方式如下:
C++20 及以上版本(最简洁)
直接用std::make_index_sequence配合lambda展开即可:
#include <array> #include <utility> template <typename T, size_t N, typename... Args> constexpr std::array<T, N> buildArray(Args&&... args) { // 生成长度为N的编译期整数序列,每个位置对应一次T对象构造 return []<size_t... Is>(std::index_sequence<Is...>, auto&&... initArgs) { return std::array<T, N>{(static_cast<void>(Is), T{std::forward<Args>(initArgs)...})...}; }(std::make_index_sequence<N>{}, std::forward<Args>(args)...); }
使用时直接指定模板参数即可适配你的场景:
// 生成64个用{init1, init2}初始化的kissfft<float>对象 std::array<kissfft<float>, 64> myArray = buildArray<kissfft<float>, 64>(init1, init2);
其中(static_cast<void>(Is), T{...})的写法是为了避免编译器告警未使用的Is参数,同时保证构造顺序符合预期。
C++11/14/17 兼容版本
如果使用旧标准,需要额外加一层辅助函数处理整数序列展开:
#include <array> #include <utility> namespace detail { template <typename T, size_t... Is, typename... Args> constexpr std::array<T, sizeof...(Is)> buildArrayImpl(std::index_sequence<Is...>, Args&&... args) { return std::array<T, sizeof...(Is)>{(static_cast<void>(Is), T{std::forward<Args>(args)...})...}; } } template <typename T, size_t N, typename... Args> constexpr std::array<T, N> buildArray(Args&&... args) { return detail::buildArrayImpl<T>(std::make_index_sequence<N>{}, std::forward<Args>(args)...); }
使用方式和C++20版本完全一致。
原理解释
std::make_index_sequence<N>会生成类型为std::index_sequence<0,1,2,...,N-1>的编译期整数序列,模板参数包展开时,序列里的每一个整数都会对应一次T{init1, init2}的构造调用,刚好填充std::array的N个元素,完全不需要元素类型支持默认构造函数。
内容的提问来源于stack exchange,提问作者SpiRelli
相关产品推荐
相关产品推荐

