4

I have written a template class A<T> and I am making use of the rule of zero (I let the compiler generate the destructor, copy/move constructors and assignment operator overloadings). However, I need now a customized assignment operator that takes a different type B<T> as argument:

A<T>& operator=(const B<T>& rhs);

Will this implementation prevent the compiler from generating the default destructor etc.? My guess is no, because the compiler generates

A<T>& operator=(const A<T>& rhs);

which is just entirely different from the overloading I want to implement.

Urwald
  • 343
  • 1
  • 10
  • 3
    IMO assignment operator and rule 3/5/0 are almost orthogonal, [this table confirms that](https://i.imgur.com/NVdnpFa.png). Almost since there is move semantics: so if you have move assignment then you should have move constructor. – Marek R May 04 '22 at 08:56
  • 1
    Thanks a lot for your comments! @MarekR One question regarding your table: I guess `A& operator=(const B& rhs);` technically is not a copy assignment, but just an assignment operator overloading, since copy assignment would need some object `A` https://en.cppreference.com/w/cpp/language/copy_assignment Does this table still hold regarding move constructor/assignment? – Urwald May 04 '22 at 09:07
  • 2
    Even `template A& operator=(const A& rhs);` is not a copy assignment. (When U==T, `A& operator=(const A&)` would be selected). – Jarod42 May 04 '22 at 09:14
  • 1
    @user17732522 Yes, indeed. Also in this case, it's neither copy nor assignment operator. – Louis Go May 04 '22 at 10:15
  • See [dupe](https://stackoverflow.com/a/5625834/12002570): *"An operator template does not suppress generation of the implicitly-declared copy assignment operator."* – Jason Aug 29 '22 at 04:06

1 Answers1

5

According to my understanding, adding a operator= overload will not prevent the compiler from generating the default one according to the rule of 0.

I base this understanding on the fact that your operator= overload is not in fact a copy assignment, nor a move assignment.
Therefore the rules about generaing default constructors and assignment operators are not relevant.

I verified it with MSVC.

You can use the code below to verify with your compiler:

#include <iostream>

template <typename T>
struct B
{
    B(T const & n) : bn(n) {}
    T bn{ 0 };
};

template <typename T>
struct A
{
    A(T const & n) : an(n) {}
    A<T>& operator=(const B<T>& rhs)
    {
        an = rhs.bn;
        return *this;
    }
    T an{ 0 };
};

int main()
{
    A<int> a1{ 5 };
    A<int> a2{ 6 };
    std::cout << a2.an << ",";
    a2 = a1;    // Use default assinment
    std::cout << a2.an << ",";
    B<int> b{ 3 };
    a2 = b;     // Use custom assignment
    std::cout << a2.an << std::endl;
    return 0;
}

The output should be: 6,5,3:

6 is the value A<int> a2 is constructed with, 5 is the value assigned from A<int> a1, and 3 is the value assigned from B<int> b.

Note: an alternative would be to use a user-defined conversion function, as @LouisGo commented (see above).

wohlstad
  • 12,661
  • 10
  • 26
  • 39