I am trying to use variadic template and constructor arguments to initialise values of a multi dimensional arrays inside a custom class ArrayND
. Up until this point I've been successful initialising arbitrary dimensional Array
instances with multi dimensional std::arrays
, but the double bracing that's mostly but not always needed for std::array
initialisation gets a bit ugly and hard to parse, for example:
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},
}
});
So far, I can initialise a 1D implementation of the Array class without trouble, although I'd rather require a single set of curly braces around the values in this instance:
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
);
But I'm not sure if/how it's possible to do a similar thing to cleanly initialise higher dimensional arrays. I've been experimenting with the Array2D, but neither version of the initialisation I've pasted below works:
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 } }
);
However, the eventual goal is to be able to do the same thing with my ArrayND currently which looks like this:
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;
};
Anyone got any ideas on how to achieve something like this without passing in a multi dimensional std::array
?
To clarify, the constexpr
constructor is important to what I need to do. I have a std::vector
version that works just fine, but std::vector
still has no consexpr
constructor in clang 13.0 (and I'm not sure it's even accepted into the standard anyway, it's possible only MSVC implemented this feature...).
EDIT:
It's possibly worth noting that in the non-cutdown implementations, these arrays will all derive from the final ND class, with specialisations for scalar and 1D versions. The Array1D and Array2D classes are just for testing solutions to this issue in a simpler form.
UPDATE:
I'd rather not end up managing and writing algorithms for C arrays if I can avoid it, but it occurred to me I hadn't tried at least using them for construction... But I I'm struggling to get that working as well:
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);