0

Problem

I have a Matrix class that is able to do some math. It holds its data in a double nested std::array as a variable. I have a constructor that takes an array reference as a variadic template. I did this so i could add some SFINAE more easily (omitted here).

#include <array>

template <std::size_t N, std::size_t M, typename T>
class Matrix{
  public:

    template <typename... TArgs>
    Matrix(TArgs const(&&... rows)[M]) {
        // ??
    }

  // ...

  private:
    std::array<std::array<T,M>, N> data;
};

Question

How can i initialize the double nested array inside the constructor?

mtosch
  • 351
  • 4
  • 18
  • How should we determine `N`? Just size of that pack? – Evg Dec 15 '20 at 16:52
  • 1
    You initialize members in the initializer list, not in the constructor body. – super Dec 15 '20 at 16:54
  • yeah, it's the size of the pack. N and M are known at compile time. basically the all sizes (i.e. matrix dimensions) are fixed which should make it easier to initialize... – mtosch Dec 15 '20 at 16:55
  • godbolt here: https://godbolt.org/z/GP9369 – mtosch Dec 15 '20 at 16:57
  • I don't understand `const &&` usage here. They typically come [apart](https://stackoverflow.com/questions/24824432/what-is-use-of-the-ref-qualifier-const). – Evg Dec 15 '20 at 17:26

2 Answers2

2

With the not shown constraint than sizeof..(TArgs) == N and types are T, you might store address of rows in array pointer and then work normally

template <typename... TArgs>
Matrix(TArgs const(&&... rows)[M]) {
    using Arr = const T (*)[M];
    const Arr args[N] = {&rows...}; // or const T (*args[N])[M] = {&rows...};

    for (std::size_t i = 0; i != N; ++i) {
        for (std::size_t j = 0; j != M; ++j) {
            data[i][j] = (*args[i])[j];
        }
    }
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

With std::to_array that would be part of C++20, we could simply write:

template<std::size_t N, std::size_t M, typename T>
class Matrix {
public:
    template<typename... Args>
    Matrix(const Args(&... rows)[M]) : data{std::to_array(rows)...}
    {}

private:
    std::array<std::array<T, M>, N> data;
};

Until C++20 we can copy-paste to_array implementation from here, which will add a few more lines to this solution.

Simplified implementation:

template<std::size_t N, typename T, std::size_t... is>
std::array<T, N> to_array_impl(const T(& arr)[N], std::index_sequence<is...>) {
    return std::array<T, N>{arr[is]...};
}

template<std::size_t N, typename T>
std::array<T, N> to_array(const T(& arr)[N]) {
    return to_array_impl(arr, std::make_index_sequence<N>{});
}

With member list initialization you would be able to initialize const data, too.

Evg
  • 25,259
  • 5
  • 41
  • 83
  • unfortunately i have to use c++14. but i tried your simplified implementation of `to_array` and it works nicely – mtosch Dec 15 '20 at 17:23