Let's consider following illustrative example code:
using matrix_t = double[2][2];
constexpr matrix_t zero_matrix = {
{0.0, 0.0},
{0.0, 0.0}
};
constexpr matrix_t identity_matrix = {
{1.0, 0.0},
{0.0, 1.0}
};
struct wrapped_matrix_t
{
matrix_t matrix;
};
constexpr wrapped_matrix_t zero_wrapped_matrix = {
//zero_matrix
{
{zero_matrix[0][0], zero_matrix[0][1]},
{zero_matrix[1][0], zero_matrix[1][1]}
}
};
constexpr wrapped_matrix_t identity_wrapped_matrix = {
//identity_matrix
{
{identity_matrix[0][0], identity_matrix[0][1]},
{identity_matrix[1][0], identity_matrix[1][1]}
}
};
Now I would like to be able to use by constexpr
arrays zero_matrix
and identity_matrix
to initialize matrix_t
members in other types. However that seems to not be possible. Or at least simple use of the name doesn't work.
The best what I come out with is reuse of values be referring to indexes. But this is far from perfect.
Is there any way to use zero_matrix
and identity_matrix
directly in such initializations?
(I'm checking on GCC 6.3.0 with -Wall -Wextra -pedantic -std=c++11
.)
If you cannot use std::array
and don't have access to the implementation of wrapped_matrix_t
, you can use metaprogramming to generate the indexing of the source array when initializing your wrappers. The final code will look like this:
constexpr wrapped_matrix_t zero_wrapped_matrix = from_array(zero_matrix);
constexpr wrapped_matrix_t identity_wrapped_matrix = from_array(identity_matrix);
I'm assuming that matrix_t
is double[2 * 2]
, but the technique below can be generalized to N
-dimension arrays.
Here are the implementation details:
template <typename Array, std::size_t... Is>
constexpr auto from_array_impl(const Array& arr, std::index_sequence<Is...>)
{
return wrapped_matrix_t{arr[Is]...};
}
template <std::size_t N>
constexpr auto from_array(const double(&arr)[N])
{
return from_array_impl(arr, std::make_index_sequence<N>());
}
I'm basically matching the size of the array with a reference, and building a 0..N
index sequence from it. I'm then creating a wrapped_matrix_t
by indexing the array with the sequence.
Here's a possible implementation for 2D arrays:
template <std::size_t W, typename Array, std::size_t... Is>
constexpr auto from_array_impl(const Array& arr, std::index_sequence<Is...>)
{
return wrapped_matrix_t{(arr[Is % W][Is / W])...};
}
template <std::size_t W, std::size_t H>
constexpr auto from_array(const double(&arr)[W][H])
{
return from_array_impl<W>(arr, std::make_index_sequence<W * H>());
}