关于函数/运算符重载的混淆

时间:2014-09-09 20:07:56

标签: c++

考虑以下自包含程序。

#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)
}

FooBar都会重载赋值运算符,并且在使用它们时都无法编译,除非我们将它显式地转换为对象的类型。但是,FooBar的分配失败了,但失败却不同。注意,我确实理解为什么当函数根据引用和值重载时调用是不明确的。但我不明白的是

  1. 为什么使用显式模板参数会更改编译器失败。声明(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 ='
    
  2. 为什么执行显式转换的(3)和(4)都不会失败。为什么它不是模棱两可的,也不试图访问私有的引用过载。

  3. 为什么在情况(2)中,与重载函数/运算符的值相比,它优先考虑引用过载。
  4. 注意 IDEONE版本,以防您想要使用代码。 注意您能否提供适当的参考资料。

1 个答案:

答案 0 :(得分:5)

  1. Foo::operator=的两个重载都是用于重载解析目的的同样好的匹配 - 因此含糊不清。 Bar::operator=的情况并非如此 - 在其他条件相同的情况下,重载解析更喜欢非模板而不是模板。因此私有operator=是更好的匹配 - 但当然它无法进行访问检查。

  2. Foo<int>(f2)是临时的,无法绑定到非const引用。以值为参数的过载是唯一可行的候选者。

  3. 它没有优先考虑引用过载 - 它优先考虑非模板重载。您可以通过切换它们来确认。