考虑以下自包含程序。
#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)
}
Foo
和Bar
都会重载赋值运算符,并且在使用它们时都无法编译,除非我们将它显式地转换为对象的类型。但是,Foo
和Bar
的分配失败了,但失败却不同。注意,我确实理解为什么当函数根据引用和值重载时调用是不明确的。但我不明白的是
为什么使用显式模板参数会更改编译器失败。声明(1)和(2)给出了不同的错误,其中(1)声称呼叫是模糊的,其中(2)声称它不能访问私人数据成员。对于前者在使用VC ++进行编译时(与g ++类似),我看到以下错误
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 ='
为什么执行显式转换的(3)和(4)都不会失败。为什么它不是模棱两可的,也不试图访问私有的引用过载。
注意 IDEONE版本,以防您想要使用代码。 注意您能否提供适当的参考资料。
答案 0 :(得分:5)
Foo::operator=
的两个重载都是用于重载解析目的的同样好的匹配 - 因此含糊不清。 Bar::operator=
的情况并非如此 - 在其他条件相同的情况下,重载解析更喜欢非模板而不是模板。因此私有operator=
是更好的匹配 - 但当然它无法进行访问检查。
Foo<int>(f2)
是临时的,无法绑定到非const引用。以值为参数的过载是唯一可行的候选者。
它没有优先考虑引用过载 - 它优先考虑非模板重载。您可以通过切换它们来确认。