I have a struct
that holds an array, and I'd like to pass an initializer list to the struct's constructor to be forwarded on to the array. To illustrate, I tried:
#include <initializer_list>
struct Vector
{
float v[3];
Vector(std::initializer_list<float> values) : v{values} {}
};
int main()
{
Vector v = {1, 2, 3};
}
Which resulted in the error:
error: cannot convert ‘std::initializer_list<float>’ to ‘float’ in initialization
I tried using parentheses instead of braces for v
but that gave the error:
error: incompatible types in assignment of ‘std::initializer_list<float>’ to ‘float [3]’
My main motivation for trying to do this is to avoid the following warning that clang generates:
template <int N>
struct Vector
{
float v[N];
};
template <>
struct Vector<2>
{
float x, y;
};
int main()
{
Vector<2> v2 = {1.0f, 2.0f}; // Yay, works
Vector<3> v3 = {1.0f, 2.0f, 3.0f}; // Results in warning in clang++
Vector<3> u3 = {{1.0f, 2.0f, 3.0f}}; // Must use two braces to avoid warning
// If I could make Vector<N> take an initializer list in its constructor, I
// could forward that on to the member array and avoid using the double braces
}
warning: suggest braces around initialization of subobject
So my question is: How can I initialize a member array with an initializer list? (i.e. How can I make the first code work? Or is it not possible?
Plain C style arrays are not assignable. If you switch over to using std::array
instead, the initialization becomes trivial.
#include <array>
struct Vector
{
std::array<float, 3> v;
Vector(std::array<float, 3> const& values)
: v(values)
{}
};
int main()
{
Vector v{{1, 2, 3}};
}
If your class is an aggregate, you can use your syntax
template < std::size_t len >
struct Vector
{
float elems[len];
};
Vector<3> v = {1.0f, 2.0f, 3.0f};
Note: this is possible due to brace-elision. No need for v = {{1,2,3}};
though this is also possible. Clang issues this warning because the clearer and less error-prone syntax is with the double braces (one for initializing v
and one for initializing the sub-aggregate elems
).
If your class is not an aggregate, you can use variadic templates:
#include <array>
#include <cstddef>
template < std::size_t len >
struct Vector
{
std::array < float, len > m; // also works with raw array `float m[len];`
template < typename... TT >
Vector(TT... pp) : m{{pp...}}
{}
// better, using perfect forwarding:
// template < typename... TT >
// Vector(TT&&... pp) : m{{std::forward<TT>(pp)...}}
// {}
};
Vector<3> a = {1.0f, 2.0f, 3.0f};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With