My question was, how the displayed behaviour could be prevented, but as Cheersandhth.-Alf pointed out, I failed to include my constructor which caused this problem. The constructor is now included and it is obvious, that forwarding the float (aswell as anything else) to the std::array ctor caused this problem.
I would still like to be able to use this kind of initialization Vec2 a = {1.f, 2.f}
, but the forwarding ctor is pretty dangerous, so I will avoid that.
I have a Vec class derived from std::array which is supposed to implement the usual component-wise arithmetic operations via operator overloads. The operators should be implemented both for other Vecs of the same type and size (in that case operating on the corresponding vector components), aswell as integral and floating point types.
e.g.
{1.f, 2.f, 3.f} * 2.f = {2.f, 4.f, 6.f}
{1.f, 0.f} + {0.f, 1.f} = {1.f, 1.f}
Here is what I did (only shown for operator*) https://godbolt.org/g/PtCkzR:
template<class T, size_t N>
class Vec : public std::array<T, N>
{
public:
template<typename... S>
Vec(S&&... params) : std::array<T, N>{std::forward<S>(params)...} { };
friend Vec<T, N>& operator*=(Vec<T, N>& a, const Vec<T, N>& b)
{
std::transform(a.begin(), a.end(), b.begin(), a.begin(), std::multiplies<>());
return a;
}
template<class S>
friend Vec<T, N>& operator*=(Vec<T, N>& a, const S& b)
{
std::transform(a.begin(), a.end(), a.begin(), [&] (T x) { return x*b; });
return a;
}
template<class S>
friend Vec<T, N> operator*(Vec<T, N> a, const S& b)
{
return a *= b;
}
};
using Vec2 = Vec<float, 2>;
Now, when I want to multiply a vector with a float this happens:
Vec2 a{1.f, 1.f};
auto b = a * 0.5f; // b = {.5f, .5f} <- as expected
auto c = 0.5f * a; // c = {.5f, 0.f} <- what happened here?
This happens because the 0.5f
in the third line is implicitly converted to a Vec2 {0.5f, 0.f}
and is then passed to the operator*(Vec2, const Vec2&)
overload.