模板赋值运算符重载神秘

时间:2011-04-11 18:32:56

标签: c++ templates assignment-operator

我有一个简单的结构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;

b分配给a将使用上面的非常量模板赋值运算符重载,并显示数字“2”。

让我感到困惑的是:如果我宣布cd

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

并将d分配给c,两个赋值运算符重载都没有使用,也没有显示输出;因此调用默认的复制赋值运算符。为什么将d分配给c不使用提供的const重载赋值运算符?或者,为什么分配ba 使用默认的复制赋值运算符?

2 个答案:

答案 0 :(得分:18)

  

为什么将d分配给c不使用提供的const重载赋值运算符?

仍然会生成隐式声明的复制赋值运算符,该运算符声明如下:

Wrapper& operator=(const Wrapper&);

运算符模板不会抑制隐式声明的复制赋值运算符的生成。由于参数(const-qualified Wrapper)与此运算符(const Wrapper&)的参数完全匹配,因此在重载决策期间选择它。

未选择运算符模板,并且没有歧义,因为 - 所有其他条件相同 - 非模板在重载决策期间比模板更好地匹配。

  

为什么将b分配给a不使用默认的副本分配运算符?

参数(非const限定的Wrapper)更适合采用Wrapper<U>&的运算符模板,而不是隐式声明的复制赋值运算符(需要{{1} }}

答案 1 :(得分:6)

来自C ++ 03标准,§12.8/ 9:

  

用户声明的复制赋值运算符X::operator=是类X的非静态非模板成员函数,其中只有一个X类型的参数,X&const X&volatile X&const volatile X&

§12.8/ 10:

  

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

您的operator=是模板的事实使得一个复制赋值运算符,因此编译器仍会生成类的隐式复制赋值运算符。