[C++] Ambiguous operator usage after adding template friends

Started by
4 comments, last by Falken42 14 years, 6 months ago
So I thought it would be a great idea to add template friends to my class for the standard operators (add, subtract, etc.), so I could do cool things like a = 1 / b;, but I seem to have run into a bit of a problem. While gcc-4.4.0 accepts the following code just fine, both VS2005 and Comeau give an error about being ambiguous as to which operator to choose:
template <typename T>
class MyClass
{
public:
	MyClass() : mVal(0) { }
	MyClass(T val) : mVal(val) { }

	template <typename U> MyClass<T> operator +(U val) const
	{
		MyClass<T> res = *this;
		res.mVal += val;
		return res;
	}

	template <typename U> friend MyClass<T> operator +(U val, const MyClass<T> &myc)
	{
		return myc + val;
	}

private:
	T mVal;
};

int main()
{
	MyClass<int> a, b, c;
	c = a + b;
}

Here's the actual error from Comeau (VS2005's error is pretty much the same):
"ComeauTest.c", line 27: error: more than one operator "+" matches these operands:
            function template "MyClass<int> operator+(U, const MyClass<int> &)"
            function template "MyClass<int> MyClass<T>::operator+(U) const
                      [with T=int]"
            operand types are: MyClass<int> + MyClass<int>
  	c = a + b;
  	      ^
Any suggestions on what I might be doing wrong here, and how to possibly fix or work around this?
Advertisement
You can create an operator+(const MyClass<T> &, const MyClass<T> &) which (I think) will be chosen over the other two versions.
The problem is that neither of the operator+ versions takes two MyClass instances!

Curiously GCC compiles it, instantiates the friend version, and ends up in an infinite loop at runtime.

I think, all you need is operator+ that takes two MyClasses (of independent type), since the non-explicit constructor allows implicit conversion of either operand into MyClass.
That seemed to do the trick. VS2005, gcc, and Comeau all compile without a problem after adding an explicit operator+ friend with MyClass<T> for both parameters.

Thanks!
My point was that you shouldn't need anything special for built-in types at all. The constructor implicitly converts those into MyClass.

template <typename T>class MyClass{public:    MyClass() : mVal(0) { }    MyClass(T val) : mVal(val) { }    friend MyClass<T> operator+(const MyClass<T>& left, const MyClass<T>& right)    {        return MyClass<T>(left.mVal + right.mVal);    }private:    T mVal;};int main(){    MyClass<int> a, b, c;    c = a + b;    c = a + 1; //implicitly converts right operand    c = 2 + b; //implicitly converts left operand    c = 1 + 2; //sums 1 + 2, then converts implicitly}
Oh, I see what you mean -- that works even better as I can remove the other operator+ function. I didn't expect the compiler to automatically use the constructor in order to convert other types when applying the operator.

I just recompiled with VS2005 and gcc, and it works fine. Thanks again!

This topic is closed to new replies.

Advertisement