11

Is there a reason to use the “canonical” signatures for operator=

class X {
  X& operator=(const X&) = delete;
  X& operator=(X&&) = delete;
};

instead of just

class X {
  void operator=(X) = delete;
};

when all you want to do is delete it?

Upd:
Also, consider a situation when X has an explicitly declared move or copy constructor.

class X {
public:
  X(X&&);
};

In that case op=(X&&) and op=(const X&) are implicitly deleted, but I want to explicitly express that assignment is not allowed.

Abyx
  • 12,345
  • 5
  • 44
  • 76
  • Does your version even work? The compiler doesn't define that version on its own, so deleting it shouldn't have any effect. – Mark Ransom Dec 09 '15 at 18:29
  • @MarkRansom you can delete whatever you want. It's not `=default` – Abyx Dec 09 '15 at 18:30
  • 2
    Why do you need to delete both the copy and move assignment operators in the first example? `X& operator=(const X&) = delete;` alone should be enough, no? A move assignment operator will not be implicitly declared due to the presence of your user declared copy assignment operator. – Praetorian Dec 09 '15 at 18:31
  • @MarkRansom Seems to work in a simple example: http://ideone.com/DAuDFH. – Fantastic Mr Fox Dec 09 '15 at 18:36
  • @Praetorian, I don't really need it. I just I want to explicitly say that `X` is not assignable in any way. – Abyx Dec 09 '15 at 18:39
  • @Ben so the same statement both declares and deletes the function? Fascinating. P.S. using `struct` instead of `class` for a quick example will prevent the errors regarding private members. – Mark Ransom Dec 09 '15 at 18:44
  • If you want to be explicit about it, use the first version. Otherwise the second version `void operator=(X) = delete;` should also achieve the same effect, as far as I can tell. – Praetorian Dec 09 '15 at 18:51
  • 4
    As a guideline, never delete the special move members. If you do so, the best you can hope for is that you've created redundant noise. At worst, it won't do what you were hoping for. `X& operator=(const X&) = delete;` is sufficient, and succinct. – Howard Hinnant Dec 09 '15 at 18:53
  • @HowardHinnant: `X& operator=(X) = delete;` seems to be even more succinct and should also be sufficient. – Dietmar Kühl Dec 09 '15 at 19:10
  • 2
    @DietmarKühl: Yes, identical in functionality. Not more succinct though (both one liners). And questionable on readability because the `X& operator=(const X&) = delete;` is more common/familiar and so your reader has to stop and figure out why the unusual signature. Ultimately this boils down to a style issue, and I'm recommending `X& operator=(const X&) = delete;`. – Howard Hinnant Dec 09 '15 at 19:26
  • 2
    Tape this above your monitor until you have it memorized: http://stackoverflow.com/a/24512883/576911 :-) – Howard Hinnant Dec 09 '15 at 19:29
  • 1
    And unit test all 6 special member whether you have them or not like this: https://github.com/HowardHinnant/date/blob/master/test/date_test/day.pass.cpp#L62-L67 – Howard Hinnant Dec 09 '15 at 19:31

1 Answers1

6

No, there is no technical reason to use the canonical copy assignment operator signature.

As seen in the standard, [dcl.fct.def.delete] §8.4.3:

  1. A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]

Therefore a deleted function's name, in this case operator=, may only be used if the compiler finds a preferable overload resolution. However, such an overload cannot exist, as X and const X& are indistinguishable as parameters ([over.ics.rank] §13.3.3.2) and the return value is ignored.

That being said, there is a stylistic reason to use the canonical signature. The mere fact that this question exists shows that anyone reading your code may not know the meaning and assume it is doing something special. For readability's sake, I would recommend you use the familiar X& operator=(const X&) = delete;.

nwn
  • 583
  • 7
  • 23