I am writing a small math library that has Vector
and Matrix
classes. I'd like to make it convenient to intialize objects of these classes with strict rules for how they can be initialized.
The Vector
class constructor already works as i intended. It is restricted such that only the correct size N
is accepted and on top of that all arguments are of the same type (see below).
Vector
template <std::size_t N, typename T>
class Vector{
public:
template <typename... TArgs,
std::enable_if_t<
sizeof...(TArgs) == N &&
(std::is_same_v<T, std::remove_reference_t<TArgs>> && ...),int> = 0>
Vector(TArgs &&... args) : data_{std::forward<TArgs>(args)...} {}
// ...
private:
std::array<T,N> data;
}
Example initialization (works, is restricted)
Vector<3,int> v{1,2,3}
Matrix
template <std::size_t N, std::size_t M, typename T>
class Matrix{
public:
/* put restriction rules here */
Matrix(std::initializer_list<std::initializer_list<T>> lst) {
int i = 0;
int j = 0;
for (const auto &l : lst) {
for (const auto &v : l) {
data[i][j] = v;
++j;
}
j = 0;
++i;
}
}
// ...
private:
std::array<Vector<M, T>, N> data;
}
Example initialization 1 (works, is not restricted)
Matrix<2,3,int> m{ {1,2,3}, {4,5,6} }
Example initialization 2 (compiles, but shouldn't!!)
Matrix<2,3,int> m{ {1,'a',3}, {4,5,6,7,8,9} }
I wasn't able to implement the Matrix
class constructor for the double-nested initialization with a variadic template, so i used nested std::initializer_list
´s (from this post). It works, but i'd like to have the same restrictions on this constructor as for the Vector
class.
How can i do this?
regarding this post here... ::std::initializer_list vs variadic templates i can say that i don't really care for using initializer_list or a variadic template. Either one seems fine in this case, but as far as i understand getting the size of an std::initializer_list
at compile time is somewhat difficult.
To have you desired syntax, you might do:
template <typename ... Us,
std::enable_if_t<sizeof...(Us) == N && (std::is_same_v<Us, T> && ...), int> = 0>
Matrix(const Us (&... rows)[M]) {
// ...
}