Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

c++ 2 overloads have similar conversions depending on whether the operator is a member function or a global one

Ask Question Vector(int _elementsCount) : elementsCount(_elementsCount) , elements(new float[_elementsCount]) ~Vector() { delete[] elements; Vector(const Vector& rhs) { elementsCount = rhs.size(); elements = new float[elementsCount]; for (int i = 0; i < elementsCount; ++i) (*this)[i] = rhs[i]; float& operator [](int i) { return elements[i]; float operator [](int i) const { return const_cast<Vector&>(*this)[i]; int size() const { return elementsCount; /*// Dot product float operator *(const Vector& v) { float res = 0; for (int i = 0; i < size(); ++i) res += (*this)[i] * v[i]; return res; private: int elementsCount; float* elements; // Multiplication by a scalar Vector operator *(const Vector& v, float k) { Vector res(v.size()); for (int i = 0; i < v.size(); ++i) res[i] = v[i] * k; return res; // Dot product float operator *(const Vector& v1, const Vector& v2) { float res = 0; for (int i = 0; i < std::min(v1.size(), v2.size()); ++i) res += v1[i] * v2[i]; return res; void main() Vector v(2); v * 3; // ambiguous

This code compiles. But if we uncomment * operator realization in the class and comment its global realization (dot product function), then there will be an error "'Vector::operator *': 2 overloads have similar conversions", because there is an ambiguity: whether to call the multiplication by a scalar or to interpret 3 as an argument to a parametrized constructor and to call the dot product. This makes sense. But I don't get what's the difference of declaring the * operator as a member function or as a global function. I thought they should be the same in the example like above, but it's not the case.

Added. The thing I most interested in is not how to avoid the ambiguity, but why there is an ambiguity in one case (when * is declared as a member) and there is no one in the other (when * is declared as a global function).

@Quimby, yeah, but why there is an ambiguity in one case and not it another? (I added the explicit question to the end of the post.) vanger Nov 25, 2021 at 0:44 See my response in the comments on my answer. The operators that you assume are equivalent are in fact not, due to having different constness . paddy Nov 25, 2021 at 1:03
explicit Vector(int _elementsCount) { ... }

The reason for the ambiguity is that the compiler can't decide whether it should implicitly convert a int value to a Vector and invoke Vector::operator*, or implicitly convert a int value to a float and use operator*(const Vector&, float).

By using explicit, such conversions are forbidden, and you must use Vector(3) if you want "3" to be a Vector.

As a side-note, you should make the operator const, since it does not modify the object. Making it const will also allow it to be used with a const Vector:

float operator *(const Vector& v) const { ... }

Beware that will still conflict with your other overload:

float operator *(const Vector& v1, const Vector& v2) 

There is no reason to have both. Choose either the member function or the global function and remove the other.

Thanks for the answer. But can you say why does the ambiguity depends on how the function is declared (member vs global)? – vanger Nov 25, 2021 at 0:46 Your member and global declarations are not equivalent. See my comment about const-correctness. As you wrote it, your member overload is equivalent to the global overload float operator*(Vector&, const Vector&).... meaning the value on the left of * can be modified by the operator. If you define your global overload that way, you get the same error. Under the hood, the compiler has a preference to match on const references when using operators. – paddy Nov 25, 2021 at 0:59

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.