4

Consider the following code:

#include<utility>

struct S {
    void f(int) = delete;
    void f(int) && { }
};

int main() { }

It doesn't compile saying that the member method cannot be overloaded and it makes sense, of course.

On the other side, the following code compiles:

#include<utility>

struct S {
    void f(int) & = delete;
    void f(int) && { }
};

int main() {
    S s;
    // s.f(42); <-- error, deleted member method
    std::move(s).f(42);
}

Is that legal code?
Wouldn't it be possible to define two completely different interfaces within the same class, the former to be used with lvalues, the latter with rvalues?
Apart from the fact that it doesn't make much sense, but it really hurts me.
Shouldn't a deleted function be deleted as a whole, instead of deleted only if you are a lvalue?
Which is the purpose of this feature? Is it the classic obscure corner case or is there something more I can't see?

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • Side comment: `void f(int) & = delete;` is redundant. Once you define a rvalue overload function, the lvalue one is not generated, so you must provide it explicitly (and the other way around of course). – vsoftco Feb 13 '16 at 22:52
  • 1
    @vsoftco This answers my question indeed, it's legal. :-) – skypjack Feb 13 '16 at 22:55
  • I could see a use case: `operator&` You might want to delete the rvalue version only to forbid to take the address of a temporary, but otherwise allow the taking of the address. – koraxkorakos Feb 13 '16 at 23:01
  • @koraxkorakos Feel free to add an answer with such an example, it would be appreciated. Thank you. – skypjack Feb 13 '16 at 23:02
  • 3
    @koraxkorakos However you will also need to look hard for case when you want to overload `operator&` – Revolver_Ocelot Feb 13 '16 at 23:04
  • @Revolver_Ocelot. (I am typing on a phone, so sorry for premature submit if comment by inadvertedly pressing enter) I saw `operator&` member on "reference like" classes used as a result of the subscript operator on bit vector "containers". Also on special allocators. The later is not standard compliant at least in C++98, AFAIK, because the reference typedef is not allowed to be something other than `T&` – koraxkorakos Feb 13 '16 at 23:16

1 Answers1

7

Sometimes it makes sense to prohibit certain operations if object is l- or r-value.

Imagine RAII wrapper for FILE*. It opens file in constructor, closes it in destructor, turning C feature requiring manual control to C++ exception-safe class. To interact with C interface, there is a .get() member which returns raw pointer. Someone might write:

FILE* file = CFile("file.txt").get();

It would compile, but it is wrong: file would be closed as soon, as file variable would be initialized. If you delete an r-value overload (on never provide it in the first place), then it would lead to compile-time error and save us from bug-hunting.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48