I'm working on a Vector2D class, and I think both vector addition and scalar addition make sense to be implemented with the +=/+ operators.
Trouble is, I don't really know how to work around this apparent argument ambiguity, here's what Clang says:
vector2d_test.cpp:17:16: error: use of overloaded operator
'+=' is ambiguous (with operand types 'Vector2D<float>' and 'int')
vector += 1;
~~~~~~ ^ ~~~~~~~
vector2d.hpp:34:18: note: candidate function
Vector2D<T>& operator+=(const Vector2D<T>& other)
^
vector2d.hpp:41:18: note: candidate function
Vector2D<T>& operator+=(const T summand) const
Here are the two functions:
Vector2D<T>& operator+=(const Vector2D<T>& other)
{
x += other.x;
y += other.y;
return *this;
}
template <typename S>
Vector2D<T>& operator+=(const S summand) const
{
x += summand;
y += summand;
return *this;
}
So... any idea what I can do about this?
It's not clear what you're trying to do. The operator+=
functions you post aren't legal unless they are members. And if
they are members, and you have something like:
Vector2D<float> v;
// ...
v += 1;
the Vector2D<float>::operator+=( Vector2D<float> const& )
function isn't callable, and so there can be no ambiguity. If
the functions aren't members, then they should be written:
template <typename T>
Vector2D<T>& operator+=( Vector2D<T>& lhs, Vector2D<T> const& rhs );
template <typename T, typename U>
Vector2D<T>& operator+=( Vector2D<T>& lhs, U rhs );
Even in this case, the first cannot be called with an rhs
of
type int
, so there is no ambiguity.
EDIT:
I missed the const
at the end of the second in your posting.
This is an obvious typo on your part, It still doesn't change
anything, unless you also have some implicit conversions to
Vector2D
(which is probably not a good idea); otherwise, the
first version is still not callable. If there is, for example,
an implicit conversion from int
to Vector2D
, and you call
+=
on a non-const Vector2D, then the first overload is
a better match for the implicit first argument (which results in
the this
pointer), since it is an exact match, without even
a cv conversion, but the second function is a better match for
the second argument, because the template instantiation results
in an exact match. So the call is ambiguous.
You have all written in you error message. You tried to add to your vector variable of int type, but your vector has floats. It should be:
vector += 1f;
or
vector += 1.0;
Take a look. When you have this vector:
Vector2D<float> vector;
function corresponding to this vector has header:
Vector2D<T>& operator+=(const float summand) const;
Second one doesn't matter right now. And when you try to add to your vector 1, you are trying to invoke function:
Vector2D<T>& operator+=(const int summand) const;
Which you didn't declare. That's why compiler message you an error - it can't find proper function.
Easiest way is to define the functions inside Vector2D ala:
Vector2D& operator+=(const Vector2D& rhs)
{ ...each this element += rhs's corresponding element... }
Vector2D& operator+=(const T& summand)
{ ...each this elements += summand... }
friend Vector2D operator+(Vector2D lhs, const Vector2D& rhs) { return lhs += rhs; }
friend Vector2D operator+(Vector2D lhs, const T& rhs) { return lhs += rhs; }
Notes:
- the non-member functions are
friend
s, which allows them to be defined conveniently inline
- the functions shouldn't be
const
(one was in your question)
- usual conversions will be attempted, so if
T
is float
then int
s will work just fine unless you do something funny like give Vector2D
an implicit constructor from a single int
that makes the choice of conversion ambiguous