如何用带索引的生成函数初始化std::array(支持非默认可构造类型)
解决方案
C++11/14 兼容方案
我们可以借助编译时整数序列生成0到N-1的索引,通过参数包展开调用foo(i),直接完成std::array的聚合初始化,全程不需要T支持默认构造:
#include <array> #include <utility> // 用于 std::index_sequence、std::make_index_sequence // 辅助函数:接收索引序列,展开构造array template <typename T, size_t... Indices> constexpr std::array<T, sizeof...(Indices)> build_foo_array(std::index_sequence<Indices...>) { return {{foo(Indices)...}}; // 逐个用 foo(Indices) 初始化array元素 } // 对外接口:指定T和N,生成对应array template <typename T, size_t N> constexpr std::array<T, N> make_foo_array() { return build_foo_array<T>(std::make_index_sequence<N>{}); }
使用方式:
auto arr = make_foo_array<T, N>();
C++20 简化方案
利用C++20的模板lambda,可以把辅助逻辑内联,代码更紧凑:
#include <array> #include <utility> template <typename T, size_t N> constexpr std::array<T, N> make_foo_array() { return []<size_t... Is>(std::index_sequence<Is...>) { return std::array<T, N>{{foo(Is)...}}; }(std::make_index_sequence<N>{}); }
核心原理说明
std::make_index_sequence<N>会在编译时生成包含0,1,...,N-1的整数序列,确保每个索引都是编译期常量。- 参数包展开
foo(Is)...会逐个调用foo(0)、foo(1)……foo(N-1),将返回值直接作为std::array的初始化元素。 - 整个
std::array通过聚合初始化完成构造,没有先默认初始化再赋值的过程,因此完全兼容不支持默认构造的T类型。
如果foo是constexpr函数,make_foo_array也可以保持constexpr,实现编译期构造std::array。
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

