Reputation: 325
I am making a matrix class where I want users to be able to instantiate the matrix like so:
Matrix<float, 2, 2> mat = { { 10, 20 }, { 30, 40 } };
My Matrix class is defined like so:
template<typename T, unsigned int ROWS, unsigned int COLS>
class Matrix
{
public:
Matrix(std::array<std::array<T, ROWS>, COLS> matrix)
{
// ...
}
// ...
};
However, when I try instantiating the matrix, as I did above, I get "could not convert" errors from the compiler. I don't want to use initializer lists because I want compile-time errors to be triggered if the user defines the matrix with the wrong order. Does anyone why this isn't working? and if so is there an alternative?
Upvotes: 1
Views: 392
Reputation: 13269
std::array
only supports aggregate initialization. By using the Matrix<float, 2, 2> mat = { ... };
syntax, you are requesting copy initialization, which std::array
just rejects. Note that, by taking a std::array<std::array<...>...>
as constructor parameter, you allow the following initialization syntax: Matrix<float, 2, 2> mat{{ 10, 20, 30, 40 }};
.
Most likely, what you want is a std::initializer_list
parameter.
If you want your class to act like a std::array
but with two dimensions, you might as well do what implementations of std::array
do, which is having no constructor and making the inner member public:
template<typename T, unsigned int ROWS, unsigned int COLS>
class Matrix
{
public:
T elements_[ROWS][COLS];
};
Here is the implementation of stdlibc++ (gcc): https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/array#L93. Note the declaration of _M_elems
is public (array
is a struct
here). This means that you could access _M_elems
directly if you know you are using this specific implementation of the standard library, but it's also the only way to get aggregate initialization working.
It also means you allow the syntax Matrix<float, 2, 2> mat2 = { 10, 20, 40, 40 };
.
Upvotes: 2
Reputation: 1699
This seems to work...
template<typename T, unsigned int ROWS, unsigned int COLS>
class Matrix
{
public:
Matrix(const std::array<T, ROWS> (&matrix)[COLS]) {
// ...
}
};
int main() {
Matrix<float, 2, 2> mat = {{ { 10, 20 }, { 40, 40 } }};
}
Though the error message is quite bad when it fails, and it only fails if you provide too many rows or columns!... for the same reason that std::array<int,3> a = {1,2};
is valid...
Edit:
Matrix(const T (&matrix)[COLS][ROWS]) {}
is also valid
Upvotes: 0
Reputation: 218098
Issue is that std::array
uses aggregate initialization (so might have/require extra brace), but then you might have ambiguous call with copy/move constructor :-/
Following compiles:
template <std::size_t COLS, std::size_t ROWS>
struct Matrix
{
Matrix(const std::array<std::array<float, COLS>, ROWS>&) {}
//Matrix(const std::vector<std::vector<float>>&) {}
};
int main() {
[[maybe_unused]]Matrix<3, 2> m1 = std::array{ std::array{1.f, 2.f, 3.f}, std::array{1.f, 2.f, 3.f}};
[[maybe_unused]]Matrix<3, 2> m2 ({{ {{1.f, 2.f, 3.f}}, {{1.f, 2.f, 3.f}}}});
//[[maybe_unused]]Matrix<3, 2> m3 ({ {1.f, 2.f, 3.f}, {1.f, 2.f, 3.f}}); // OK vector
}
Upvotes: 1