C++中能否使用可变模板参数初始化自定义多维容器ArrayND?
解决方案
方案1:展平参数按行优先初始化(最简单,完全兼容现有1D写法)
你可以要求所有元素按行优先顺序直接传入,参数总数等于各维度乘积即可,clang 13完全支持该方案用到的所有C++20 constexpr特性:
#include <array> #include <concepts> #include <utility> // 前向声明 template<size_t SIZE, size_t ... SUB_SHAPE> struct ArrayND; // 1D特化 template<size_t SIZE> struct ArrayND<SIZE> { using DataType = std::array<float, SIZE>; static constexpr size_t total_size = SIZE; DataType data; template<std::convertible_to<float> ... VALUES> requires (sizeof...(VALUES) == SIZE) constexpr explicit ArrayND(VALUES ... values) : data{static_cast<float>(values)...} {} }; // 高维实现 template<size_t SIZE, size_t ... SUB_SHAPE> struct ArrayND { using SubArray = ArrayND<SUB_SHAPE...>; using DataType = std::array<typename SubArray::DataType, SIZE>; static constexpr size_t total_size = SIZE * SubArray::total_size; DataType data; private: constexpr static DataType build_data(const float* vals) { DataType res{}; size_t pos = 0; for(size_t i = 0; i < SIZE; i++) { for(size_t j = 0; j < SubArray::total_size; j++) { *(&res[i][0] + j) = vals[pos++]; } } return res; } public: template<std::convertible_to<float> ... VALUES> requires (sizeof...(VALUES) == total_size) constexpr explicit ArrayND(VALUES ... values) : data(build_data(std::to_array({static_cast<float>(values)...}).data())) {} }; // 使用示例,无需任何额外大括号 constinit ArrayND<2,2> arr(0.1f, 0.2f, 0.3f, 0.4f); constinit ArrayND<5,4,6> big_arr(/* 直接传入5*4*6=120个float即可 */);
该方案优势是实现逻辑最简单,完全没有多层大括号的冗余问题。
方案2:支持嵌套大括号初始化(符合你期望的多组大括号写法)
你原有写法报错的核心原因是裸大括号初始化列表没有类型,无法被模板参数推导,所以可变参数模板无法匹配{0.1f, 0.2f}这类参数。解决方法是让高维ArrayND的构造函数接受低一维的ArrayND作为参数,利用大括号列表的隐式构造规则匹配:
// 基于方案1的1D特化,修改高维构造函数即可 template<size_t SIZE, size_t ... SUB_SHAPE> struct ArrayND { using SubArray = ArrayND<SUB_SHAPE...>; using DataType = std::array<typename SubArray::DataType, SIZE>; DataType data; template<std::convertible_to<SubArray> ... ARGS> requires (sizeof...(ARGS) == SIZE) constexpr explicit ArrayND(ARGS ... args) : data{static_cast<SubArray>(args).data...} {} }; // 使用示例 constinit ArrayND<2,2> arr( {0.1f, 0.2f}, // 每个大括号隐式构造1维ArrayND<2>实例 {0.3f, 0.4f} );
如果需要支持更外层的单组大括号写法{{0.1f,0.2f}, {0.3f,0.4f}},额外加一个接受std::array<SubArray, SIZE>参数的构造函数即可。
C数组构造失败的修复方案
你之前的C数组构造参数写法有误,数组参数会自动退化为指针,修改为数组引用即可正常工作:
template<size_t SIZE_0, size_t SIZE_1> struct Array2D { float data[SIZE_0][SIZE_1]; // 参数改为二维数组的引用,避免类型退化 constexpr explicit Array2D(const float (&values)[SIZE_0][SIZE_1]) { for(size_t i = 0; i < SIZE_0; i++) { for(size_t j = 0; j < SIZE_1; j++) { data[i][j] = values[i][j]; } } } }; // 现在可正常编译 constinit Array2D<2,2> arr({ {0.1f, 0.2f}, {0.3f, 0.4f} });
内容的提问来源于stack exchange,提问作者Iron Attorney
相关产品推荐
相关产品推荐

