7

我有一个简单的 struct 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”。

令我困惑的是:如果我声明cand d

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

和assign dto c,两个赋值运算符重载都不用,也不显示输出;因此调用了默认的复制赋值运算符。为什么分配dc使用提供的 const 重载赋值运算符?或者相反,为什么分配ba 使用默认的复制分配运算符?

4

2 回答 2

18

为什么分配dc使用提供的 const 重载赋值运算符?

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

Wrapper& operator=(const Wrapper&);

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

没有选择操作符模板,也没有歧义,因为在所有其他条件相同的情况下,非模板在重载决策期间比模板更好地匹配。

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

Wrapper与隐Wrapper<U>&式声明的复制赋值运算符(采用const Wrapper<U>&.

于 2011-04-11T18:36:21.787 回答
6

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

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

和§12.8/10:

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

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

于 2011-04-11T18:41:35.467 回答