Reputation: 63717
Consider the following self contained program.
#include <iostream>
template<typename Ty>
struct Foo
{
Foo& operator=(Foo foo){ return foo; }
private:
Foo& operator=(Foo& foo){ return foo; }
};
template<typename Ty>
struct Bar
{
template<typename U>
Bar& operator=(Bar<U> bar){ return bar; }
private:
Bar& operator=(Bar& bar){ return bar; }
};
int main()
{
Foo<int> f1, f2;
f1 = f2; // (1)
Bar<int> b1, b2;
b1 = b2; // (2)
f1 = Foo<int>(f2); // (3)
b1 = Bar<int>(b2); // (4)
}
Both Foo
and Bar
overloads the assignment operator, and in using both of them, fails to compile, unless, we explicitly cast it to the type of the object. Also, though, the assignment from both Foo
and Bar
fails, yet the failures are different. Note, I do understand why the call is ambiguous when a function is overloaded based on reference and value. But what I fail to understand is
Why using explicit template argument changes the compiler failure. Statement (1) and (2) gives different error, where (1) claims the call is ambiguous, where as (2) claims it cannot access private data members. For ex. when compiling with VC++ (similar behavior with g++), I see the following errors
1>Source.cpp(8): warning C4522: 'Foo<int>' : multiple assignment operators specified
1> Source.cpp(20) : see reference to class template instantiation 'Foo<int>' being compiled
1>Source.cpp(21): error C2593: 'operator =' is ambiguous
1> Source.cpp(7): could be 'Foo<int> &Foo<int>::operator =(Foo<int> &)'
1> Source.cpp(5): or 'Foo<int> &Foo<int>::operator =(Foo<int>)'
1> while trying to match the argument list '(Foo<int>, Foo<int>)'
1>Source.cpp(23): error C2248: 'Bar<int>::operator =' : cannot access private member declared in class 'Bar<int>'
1> Source.cpp(15) : see declaration of 'Bar<int>::operator ='
Why both (3) and (4) where I perform an explicit cast doesn't fail. Why it isn't ambiguous nor its trying to access the reference overload which is private.
Note An IDEONE version in case you want to play with the code. Note Can you please provide appropriate references.
Upvotes: 1
Views: 287
Reputation: 52471
Both overloads of Foo::operator=
are equally good matches for overload resolution purposes - hence ambiguity. That's not the case for Bar::operator=
- other things equal, overload resolution prefers non-templates over templates. So the private operator=
is a better match - but of course it then fails access check.
Foo<int>(f2)
is a temporary, and can't bind to non-const reference. The overload taking its parameter by value is the only viable candidate.
It doesn't give preference to reference overload - it gives preference to non-template overload. You can confirm that by switching them around.
Upvotes: 5