8

I have a simple struct Wrapper, distinguished by two templated assignment operator overloads:

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;
  }
};

I then declare a and b:

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

assigning b to a will use the non-const templated assignment operator overload from above, and the number "2" is displayed.

What puzzles me is this: If I declare c and d,

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

and assign d to c, neither of the two assignment operator overloads is used, and no output is displayed; so the default copy assignment operator is invoked. Why does assigning d to c not use the const overloaded assignment operator provided? Or instead, why does assigning b to a not use the default copy assignment operator?

user2023370
  • 10,488
  • 6
  • 50
  • 83

2 Answers2

18

Why does assigning d to c not use the const overloaded assignment operator provided?

The implicitly-declared copy assignment operator, which is declared as follows, is still generated:

Wrapper& operator=(const Wrapper&);

An operator template does not suppress generation of the implicitly-declared copy assignment operator. Since the argument (a const-qualified Wrapper) is an exact match for the parameter of this operator (const Wrapper&), it is selected during overload resolution.

The operator template is not selected and there is no ambiguity because--all other things being equal--a nontemplate is a better match during overload resolution than a template.

Why does assigning b to a not use the default copy assignment operator?

The argument (a non-const-qualified Wrapper) is a better match for the operator template that takes a Wrapper<U>& than for the implicitly-declared copy assignment operator (which takes a const Wrapper<U>&.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    +1 for *An operator template does not suppress generation of the implicitly-declared copy assignment operator*. – Nawaz Apr 11 '11 at 18:41
6

From the C++03 standard, §12.8/9:

A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.

And §12.8/10:

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.

The fact that your operator= is a template makes it not a copy assignment operator, so the class' implicit copy assignment operator is still generated by the compiler.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • What is it then if not a copy assignment operator? So what are you supposed to do instead - just make a CopyFrom function template or something like that? – David Doria Dec 09 '15 at 22:53
  • @DavidDoria : It's an assignment operator, just not a _copy_ assignment operator. – ildjarn Jun 11 '16 at 22:33