11

Possible Duplicate:
Why do C++11-deleted functions participate in overload resolution?

I have two questions about the following C++11 code:

#include <iostream>

using namespace std;

struct A {
  A()  { cout << "Default c-tor" << endl; }
  A(const A&)  { cout << "Copy c-tor" << endl; }
  A(A&&) = delete;
};

A f()
{
 A a;
 return a;
}

int main()
{
  A b = f();
  return 0;
}

I get the following compile errors with gcc and clang

gcc-4.7.2 (g++ --std=c++11 main.cpp):

main.cpp: In function ‘A f()’:
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
main.cpp: In function ‘int main()’:
main.cpp:21:10: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here

clang-3.0 (clang++ --std=c++11 main.cpp):

main.cpp:19:4: error: call to deleted constructor of 'A'
        A b = f();
          ^   ~~~
main.cpp:8:2: note: function has been explicitly marked deleted here
        A(A&&) = delete;
        ^
1 error generated.
  • Shouldn't the compiler use the copy constructor if the move constructor is explicitly deleted?
  • Does anyone know any use for "non-movable" types?

Thanks in advance.

Community
  • 1
  • 1
lucasmrod
  • 260
  • 2
  • 9
  • 1
    http://stackoverflow.com/questions/14085620/why-do-c11-deleted-functions-participate-in-overload-resolution – paulm Dec 29 '12 at 20:28
  • I'm wondering how would one return local object if `A(A&&)` is deleted. – Nawaz Dec 29 '12 at 20:55
  • Actually that was my first question, shouldn't the compiler pick the copy constructor instead of the move constructor when the move constructor is explicitly deleted? (I understood the fact that deleted functions are considered in overload resolution) – lucasmrod Dec 31 '12 at 15:28

4 Answers4

6
A(A&&) = delete;

Declaring and defining it as delete does still declare it, and does not make it completely non-existent. Rather, it's similar (but not identical) to declaring it empty and private. Like so:

private: 
  A(A&&){}

In fact, that was the trick sometimes used for other operators before = delete was available. Again, it exists in the sense of lookup, but calling it is not ever allowed and in C++ calling permissions are (in almost or all cases) done after everything else, such as overload resolution, name lookup.

The standard actually say (8.4.3)

A deleted function is implicitly inline.

And there's noting (that I find) saying that deleted functions should not participate in name lookup.

Also, from 8.4.3

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.

Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
  • 2
    @Nawaz: it's the same as the other two answers, since if it was truly "non-existent" then it wouldn't be considered in overload resolution. Ofc I wouldn't put it past the standard to introduce a technical definition of "existent" that contradicts the English meaning ;-) It's considered for some purposes but not others, although it has no function body so it's different from the defined private function above. – Steve Jessop Dec 29 '12 at 20:25
  • @SteveJessop: By existent, Johan meant something that is not true. He tried to explain what he meant by showing the equivalent code : he *defined* it in the private section. – Nawaz Dec 29 '12 at 20:28
  • 1
    @Nawaz: shrug. Of course I don't know what's in Johan's mind but I'm pretty sure it's about the same as the other two answerers. – Steve Jessop Dec 29 '12 at 20:30
  • @JohanLundberg: If `delete`d move-constructor means it is defined in the `private` means, the member functions of the class would be use it, which is not true. Hence that is not equivalent, and it doesn't mean it is `private`. If you left it *undefined* (only declaration in the private section), then that would be close to an equivalent code, but even then it is not *exactly* equivalent. – Nawaz Dec 29 '12 at 20:32
  • @Johan: now I'm starting to disagree with you, I think it goes too far to say that *in fact* it's empty. Since the function cannot ever be called or otherwise referenced, you can say that it's "a bit like" it had an empty body but equally you can say that it's "a bit like" it had some other body contents that you might imagine. – Steve Jessop Dec 29 '12 at 20:32
  • @Johan: it was the comment I was (slightly) disagreeing with rather than the answer. I think at time of writing the only thing I disagree with in the answer is the statement that "that was the trick often used". The trick I've often seen and used is to declare the constructor private but *not* define it. Your way, if you access the constructor accidentally from the class itself (or a friend) you get unexpected and presumably broken behaviour. My way you get a linker error. – Steve Jessop Dec 29 '12 at 20:38
  • @SteveJessop: But deleted constructor would give you compilation-error as opposed to linker-error, that means it is not equivalent, and saying "it is existing" sounds misleading to me. – Nawaz Dec 29 '12 at 20:42
  • 1
    @Nawaz: sure, Johan never said it was equivalent. Tbh I'm not certain the the comparison with a private constructor is all that fruitful. It's a replacement for that technique but it works somewhat differently. But I agree that it's similar. – Steve Jessop Dec 29 '12 at 20:43
  • @SteveJessop: He implied it very much. The answer has been edited now. – Nawaz Dec 29 '12 at 20:44
  • @Nawaz: the very first version of this answer that I saw stated that it was similar. To me, "similar" implies "not equivalent". If you're claiming something different that happened inside the free edit window, well, I can't prove otherwise :-) – Steve Jessop Dec 29 '12 at 20:45
  • @SteveJessop: the term *"similar"* is added later :P. The first version did NOT have this term. – Nawaz Dec 29 '12 at 20:45
  • I never said it was the same, but I think this is getting silly. This is not really a hard question. Like my answer or not, or comment on the current version – Johan Lundberg Dec 29 '12 at 20:46
2

This is a bit of a research task but I think declaring a move constructor states that the move constructor is to be considered. When it then gets deleted, it means that objects can be moved where they could be moved if there were a move constructor. If you want an object which isn't moved but copied, you'd just declare a copy constructor and you wouldn't mention the move constructor.

I haven't quite found the statement in the standard, yet, which explicitly states the above but there is Note in 12.8 [class.copy] paragraph 9 backing up part the above statement:

[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
2

When you delete the move constructor, it doesn't remove it from the set of functions found by name lookup. Whenever your code would normally use the move constructor, you will get an error because, even though it was found, it has been deleted.

You have two moves in your code. The first is when you return a because when copy elision is possible and the object that would be copied is designated by an lvalue (a, here), it is treated as a move. The second is in the assignment A b = f(), because a f() is giving you a temporary that has not yet been bound to a reference.

If you want the copy constructor to be found rather than the deleted move constructor, you should just get rid of your deleted definition.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
1

From C++ Working Draft 2012-11-02

8.4.3 Deleted definitions [dcl.fct.def.delete]
...
2 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 ]
...
4 A deleted function is implicitly inline.

Since the deleted move constructor is referenced, the program is ill-formed.

A "usage" for a non-movable type could be to prevent moving, and so prevent returning a local object. I haven't seen such a usage myself and I don't know whether this makes sense at all, but YMMV.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198