2011-04-11 34 views
7

我有一个简单的结构Wrapper,由两个模板赋值运算符重载区分:模板赋值运算符重载神秘

template<typename T> 
struct Wrapper { 

    Wrapper() {} 

    template <typename U> 
    Wrapper &operator=(const Wrapper<U> &rhs) { 
    cout << "1" << endl; 
    return *this; 
    } 
    template <typename U> 
    Wrapper &operator=(Wrapper<U> &rhs) { 
    cout << "2" << endl; 
    return *this; 
    } 
}; 

然后我宣布A和B:

Wrapper<float> a, b; 
a = b; 

分配ba将使用显示非常量模板赋值运算符从上方过载,并显示数字“2”。

令我百思不解的是这样的:如果我宣布cd

Wrapper<float> c; 
const Wrapper<float> d; 
c = d; 

,并分配给dc,既不使用两种赋值操作符重载,并且不显示输出;所以调用默认的复制赋值操作符。为什么将d分配给c不使用提供的const重载赋值运算符?或者相反,为什么分配ba而不是使用默认的复制赋值运算符?

回答

18

为什么指定dc不使用const重载赋值运算符提供?

的隐式声明的拷贝赋值运算符,其声明如下,仍然产生:

Wrapper& operator=(const Wrapper&); 

操作员模板不抑制隐式声明的拷贝赋值运算符的产生。由于参数(一个const限定的Wrapper)与此运算符的参数(const Wrapper&)完全匹配,所以在重载解析期间会选择它。

运算符模板没有被选中,并且没有歧义,因为 - 所有其他条件相同 - 非模板在重载解析期间比模板更好匹配。

为什么分配ba不使用默认的复制赋值运算符?

的参数(非const限定Wrapper)是操作员模板,更好的匹配,需要一个Wrapper<U>&比隐式声明的拷贝赋值运算符(这需要一个const Wrapper<U>&

+1

+1 for *运算符模板不抑制隐式声明的复制赋值运算符*的生成。 – Nawaz 2011-04-11 18:41:38

6

从C++ 03标准,§12.8/ 9:

甲用户声明的复制赋值运算符X::operator=X类的正好与一个非静态非模板成员函数参数类型XX&,const X&,volatile X&const volatile X&

和§12。8/10:

如果类定义没有显式声明复制赋值运算符,则会隐式声明一个。

的事实,你operator=是一个模板,使得它一个拷贝赋值运算符,所以类隐拷贝赋值运算符仍然由编译器生成。

+0

那么如果不是复制赋值操作符,它又是什么?那么你应该怎么做 - 只要制作一个CopyFrom函数模板或类似的东西? – 2015-12-09 22:53:27

+0

@DavidDoria:这是一个赋值操作符,不是_copy_赋值操作符。 – ildjarn 2016-06-11 22:33:05