Reputation: 611
I am trying to implement a Matrix class by defining rows and columns as template parameters. Also, I consider the Vector as a 'degraded' matrix class that share most of its code.
I would like to initialize my classes using initializers lists, as it was used in old c arrays way.
The problem comes when trying to give one and only one constructor to the class depending of being a Matrix or a Vector, so it is forbides in compiling time to assign a matritial initializer list to a vector and a vectorial initializer list to a matrix. I have tried with templates and with std::enable_if, but I am not able to fully understand the weird error messages of the compiler.
I post the reduced code stating the problem, clean of all of trials to solve it. In the comments I include further explanation of what I am trying to do. Anyone can knows how to do what I need?
#include <initializer_list>
template<int R, int C, typename T=int>
struct Matrix
{
T data[R][C];
Matrix(std::initializer_list<T> initializers) { }//Do some stuff inside
Matrix(std::initializer_list<std::initializer_list<T>> initializers) { }//Do some stuff inside
};
template<int R, typename T=int>
using Vector = Matrix<R, 1, T>;
int main()
{
Matrix<3, 3> m = { {1, 2, 3},
{4, 5, 6},
{7, 8, 9} };
Vector<3> v = {10, 20, 30};
Matrix<3, 3> m1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//This must be avoided using templates in constructors or SFINAE
Vector<3> v1 = { {10, 20, 30} };//This must be avoided using templates in constructors or SFINAE
return 0;
}
Also, I post a coliru link with this same code: http://coliru.stacked-crooked.com/a/17b5e8c504c262d1
Thank you very much in advance.
Upvotes: 0
Views: 178
Reputation: 217225
With C++20, you might use requires
to discards overloads:
template <int R, int C, typename T=int>
struct Matrix
{
T data[R][C];
Matrix(std::initializer_list<T> initializers) requires (C == 1)
{ /*..*/ }
Matrix(std::initializer_list<std::initializer_list<T>> initializers) requires (C != 1)
{ /*..*/ }
};
Prior of that, specialization:
template <int R, int C, typename T=int>
struct Matrix
{
T data[R][C];
Matrix(std::initializer_list<std::initializer_list<T>> initializers)
{ /*..*/ }
};
template <int R, typename T>
struct Matrix<R, 1, T>
{
T data[R][1];
Matrix(std::initializer_list<T> initializers)
{ /*..*/ }
};
or SFINAE can be used:
template <int R, int C, typename T=int>
struct Matrix
{
T data[R][C];
template <typename D = C, std::enable_if_t<D == 1, int> = 0>
Matrix(std::initializer_list<T> initializers)
{ /*..*/ }
template <typename D = C, std::enable_if_t<D != 1, int> = 0>
Matrix(std::initializer_list<std::initializer_list<T>> initializers)
{ /*..*/ }
};
Upvotes: 2