1

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.)

2
  • So you want to write constexpr wrapped_matrix_t zero_wrapped_matrix{zero_matrix}; but it doesn't compile? Commented May 12, 2017 at 9:18
  • Yes. It doesn't compile. Regardless if I write it zero_wrapped_matrix{zero_matrix} or zero_wrapped_matrix = {zero_matrix}. In both cases I'm getting "error: array must be initialized with a brace-enclosed initializer". Commented May 12, 2017 at 9:35

2 Answers 2

2

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.

live example on wandbox


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>());
}

live example on wandbox

Sign up to request clarification or add additional context in comments.

3 Comments

My case contains also many other members in the wrapped_matrix_t. And they are set to different values in different constexpr variables. But I think it would be doable by extending the from_array to take those arguments as well (and probably rename it). Still this is not as nice as it would be to just use zero_matrix but I'm guessing this might be the only way. I will accept the answer after giving some more time.
@AdamBadura: you should really mention all of this extra constraints in the question, otherwise you will never get an answer that's valid for your real use case.
Well, that is always a trade-off between simplicity of the example and closeness to real case. In initial version I had wrapped_matrix_t with an extra member but in the end I removed it to shorter and cleaner example.
1

You could use std::array and change your representation to an 1D array.

using matrix_t = std::array<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};
constexpr wrapped_matrix_t identity_wrapped_matrix{zero_matrix};

live example on wandbox


In order to access the 1D array as if it was a 2D one, you can use the following formula: (x, y) => x + y * width.

It is possible to create a wrapper around std::array that provides a 2D-like interface, if you so desire.

2 Comments

In my real case I already have 1D array so one problem less! However, the wrapped_matrix_t is in my case a C POD out of my control so I cannot use std::array. Also - to be honest - this is still far from perfect solution...
@AdamBadura: added another answer with a different approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.