Тайна перегрузки оператора присваивания шаблона - PullRequest
7 голосов
/ 11 апреля 2011

У меня есть простая структура 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».

Что меня удивляет, так это: если я объявляю c и d,

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

и присвойте d на c, ни одна из двух перегрузок оператора присваивания не используется, и выходные данные не отображаются;поэтому вызывается оператор назначения копирования по умолчанию.Почему при присваивании d на c не используется предоставленный оператор перегрузки const?Или вместо этого, почему при присваивании b a , а не используется оператор копирования по умолчанию?

Ответы [ 2 ]

18 голосов
/ 11 апреля 2011

Почему присвоение d для c не использует предоставленный перегруженный оператор присваивания const?

Неявно объявленный оператор присваивания копии, который объявлен следующим образом, все еще генерируется:

Wrapper& operator=(const Wrapper&);

Шаблон оператора не подавляет генерацию неявно объявленного оператора назначения копирования. Поскольку аргумент (с константной квалификацией Wrapper) является точным соответствием параметра этого оператора (const Wrapper&), он выбирается во время разрешения перегрузки.

Шаблон оператора не выбран, и нет никакой двусмысленности, потому что - при прочих равных условиях - нет-шаблон лучше подходит при разрешении перегрузки, чем шаблон.

Почему при присвоении b a не используется оператор копирования по умолчанию?

Аргумент (не ограниченный константой Wrapper) является лучшим соответствием для шаблона оператора, который принимает Wrapper<U>&, чем для неявно объявленного оператора назначения копирования (который принимает const Wrapper<U>&.

6 голосов
/ 11 апреля 2011

Из стандарта C ++ 03, §12.8 / 9:

Объявленный пользователем оператор копирования X::operator= является нестатическим не-шаблоном членомфункция класса X с ровно одним параметром типа X, X&, const X&, volatile X& или const volatile X&.

И §12,8 / 10:

Если определение класса явно не объявляет оператор присваивания копии, он объявляется неявно.

Тот факт, что ваш operator= является шаблоном, делает его не оператор присваивания копии, так что оператор неявного присваивания копии класса все еще генерируется компилятором.

...