【发布时间】:2021-12-26 21:43:07
【问题描述】:
我正在尝试使用可变参数模板和构造函数参数来初始化自定义类 ArrayND 内的多维数组的值。到目前为止,我已经成功地用多维 std::arrays 初始化任意维 Array 实例,但是 std::array 初始化主要但并不总是需要的双支撑变得有点丑陋且难以解析,例如:
constinit ArrayND<5, 4, 6> my_nd_array({
{
{{ {0.4f}, {0.6f}, {0.1f}, {0.4f} }},
{0.4f, 0.6f, 0.1f, 0.4f},
{0.4f, 0.6f, 0.1f, 0.4f},
{0.4f, 0.6f, 0.1f, 0.4f},
{0.4f, 0.6f, 0.1f, 0.4f},
}
});
到目前为止,我可以毫无问题地初始化 Array 类的一维实现,尽管我宁愿在此实例中的值周围使用一组花括号:
template<size_t SIZE>
struct Array1D {
template<class ... VALUES>
constexpr explicit Array1D(const VALUES ... values)
: data({values...})
{}
std::array<float, SIZE> data;
};
constinit Array1D<2> my_2_array(
0.1f, 0.2f
);
但我不确定是否/如何做类似的事情来干净地初始化高维数组。我一直在尝试使用 Array2D,但我在下面粘贴的初始化版本都不起作用:
template<size_t SIZE_0, size_t SIZE_1>
struct Array2D {
template<class ... VALUES>
constexpr explicit Array2D(const VALUES ... values)
: data(values...)
{}
std::array<std::array<float, SIZE_1>, SIZE_0> data;
};
// ERROR: No matching constructor...
constinit Array2D<2, 2> my_2x2_array_A(
{ 0.1f, 0.2f }, { 0.3f, 0.4f }
);
// ERROR: No matching constructor...
constinit Array2D<2, 2> my_2x2_array_B(
{ { 0.1f, 0.2f }, { 0.3f, 0.4f } }
);
然而,最终的目标是能够用我的 ArrayND 做同样的事情,目前看起来像这样:
template<size_t SIZE, size_t ... SUB_SHAPE>
struct ArrayND {
template<class ... VALUES>
constexpr explicit ArrayND(const VALUES ... values)
: data(values...)
{}
using DataType = std::array<typename ArrayND<SUB_SHAPE...>::DataType, SIZE>;
DataType data;
};
有人知道如何在不传入多维std::array的情况下实现这样的目标吗?
为了澄清,constexpr 构造函数对我需要做的事情很重要。我有一个工作正常的std::vector 版本,但std::vector 在clang 13.0 中仍然没有consexpr 构造函数(而且我不确定它是否被标准接受,可能只有MSVC 实现了这个功能。 .).
编辑:
可能值得注意的是,在非缩减实现中,这些数组都将派生自最终的 ND 类,并专门针对标量和一维版本。 Array1D 和 Array2D 类仅用于以更简单的形式测试此问题的解决方案。
更新:
如果可以避免的话,我宁愿不为 C 数组管理和编写算法,但我突然想到,我至少没有尝试过将它们用于构造......但我很难得到也可以:
template<size_t SIZE_0, size_t SIZE_1>
struct Array2D {
constexpr explicit Array2D(const float values[SIZE_0][SIZE_1])
: data(values)
{}
float data[SIZE_0][SIZE_1];
};
// ERROR: No matching constructor...
constinit Array2D<2, 2> my_2x2_array_0(
{{ 0.1f, 0.2f }, { 0.3f, 0.4f }}
);
// ERROR: No viable conversion from 'float[2][2]' to 'Array2D<2, 2>'. Explicit constructor is not a candidate
// Personal note: It appears to be trying to use the copy constructor, which I guess kind of makes sense
constinit float raw_data[2][2] = {{ 0.1f, 0.2f }, { 0.3f, 0.4f }};
constinit Array2D<2, 2> my_2x2_array_1(raw_data);
【问题讨论】:
-
FWIW,如果您切换到使用一维数组来存储任何 Nd 数组,那么初始化变得微不足道。这也为您提供了最大的空间效率和您可以获得的缓存友好性。
-
我已经考虑过了,但是除了我对这个想法的其他抱怨之外,这并不能帮助我获得视觉上不错的 ND 数组初始化
-
理想情况下,我希望我的初始化在 n 维数组结构中每个数组正好有 1 个花括号
-
为什么不简单地将 Array2D 设为 Array1D 的 Array1D 的 typdef。与 ArrayND 相同
-
你的意思是完全去掉
std::array?
标签: c++ templates variadic-templates c++20 class-template