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.
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.
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.
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 delete
d, 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 ]
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.