For example, I have a class called Vector
that represents a vector and a class called Integer
that represents an integer.
class Integer{
public:
Integer(int v):value_(v){};
private:
int value_;
};
template<uint32_t Dim>
class Vector{
public:
Vector(int v[Dim])
://How to initialize each element of the value_ array here?
{
}
private:
Integer value_[Dim];
}
Since Integer
does not have a default constructor, you must initialize each element of the value_
array in the member initializer list of Vector
. However, since the length of the array is a template parameter, you cannot directly use something like value_{v[0], v[1], v[2]}
to initialize the value_ array.
I'm using c++14.
As you've said, if the size was known, you could write value_{v[0], v[1], v[2]}
directly.
std::index_sequence
Given that the size isn't known, you can write something like:
private:
template <std::size_t... I>
Vector(const int(&v)[N], std::index_sequence<I...>)
: value_{v[I]...} {}
public:
Vector(const int(&v)[Dims])
: Vector(v, std::make_index_sequence<Dims>{}) {}
Note: this uses a reference to an array so that the size is checked.
The pack expansion v[I]...
acts like v[0], v[1], ...
for an arbitrary amount Dims
of indices (as specified when creating the index sequence with std::make_index_sequence
.
However, since your Vector
class only contains an array member, it would be much easier to just have no constructor and rely on aggregate initialization instead.
If you had no constructor, you could write Vector<3>{1, 2, 3}
as well.
std::array
You could also have a single constructor:
// note: value_ should be std::array as well
Vector(const std::array<int, Dims>& content) : value_{content} {}
std::array
has value semantics, and trivializes the problem because you can just copy/move it around like any other object.
See What is the idiomatic way to create a fixed size std::array from a fixed size std::span?. This question is about C++20, but the solutions there are applicable to older versions as well.