sgorsten / linalg

linalg.h is a single header, public domain, short vector math library for C++
The Unlicense
854 stars 68 forks source link

Initializing a std::array of vecs #27

Closed crotron closed 3 years ago

crotron commented 3 years ago

I have the following code:

std::array<linalg::aliases::int2,8> offsets = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

This does not compile (error: too many initializers for ‘std::array<linalg::vec<int, 2>, 8>’). However, this does compile:

linalg::aliases::int2 offsets[8] = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

As does this:

std::vector<linalg::aliases::int2> offsets = { {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} };

Is it to be expected that initializing a std::array of vecs in this manner does not work, whereas a plain array or std::vector does?

sgorsten commented 3 years ago

My apologies for missing this issue when you first posted it.

The following should work as intended:

std::array<linalg::aliases::int2,8> offsets = {{ {0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1} }};

std::array<T,N> is somewhat unusual among the STL types in that it doesn't have any user-provided constructors, which would include things like a constructor from std::initializer_list<T>. Instead, std::array<T,N> is a simple aggregate, containing an array of T of length max(N,1). When you initialize a std::array, you're actually just initializing that single member, hence the requirement for the double braces.

The double braces can sometimes be omitted if the passed types satisfy certain properties, but at the moment it eludes me why this isn't the case for linalg::vec.

crotron commented 3 years ago

Thanks for the info! I must admit that I'm still not very experienced with the intricacies of C++, so it wasn't clear to me that was what was happening.

sgorsten commented 3 years ago

Not a problem. C++ is an large language with a long history and has accumulated a number of quirks and warts over the years. std::array<T,N> exists to fix certain issues with builtin C arrays (lack of value semantics, etc.) but introduces others in the desire to remain zero-overhead.