Reputation: 1520
Anybody knows why the compiler needs a copy constructor for Foo in this situation:
#include <iostream>
#include <list>
class Foo {
public:
Foo() {}
Foo(const Foo &&f) noexcept {}
Foo(const Foo &f) = delete;
~Foo() {}
};
void passFoo2(const Foo&& f) {
std::list<Foo> l;
l.push_back(std::move(f));
}
int main(int argc, char **argv) {
Foo f;
passFoo2(std::move(f));
return 0;
}
The compiler (g++) complains the copy constructor is deleted. But it should not need it in that case?
So what am I missing here?
x@ubuntu:/tmp/c++$ g++ stackoverflow.cxx -std=c++11
In file included from /usr/include/c++/4.9/list:63:0,
from stackoverflow.cxx:2:
/usr/include/c++/4.9/bits/stl_list.h: In instantiation of std::_List_node<_Tp>::_List_node(_Args&& ...) [with _Args = {const Foo&}; _Tp = Foo]:
/usr/include/c++/4.9/ext/new_allocator.h:120:4: required from void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::_List_node<Foo>; _Args = {const Foo&}; _Tp = std::_List_node<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:514:8: required from std::list<_Tp, _Alloc>::_Node* std::list<_Tp, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const Foo&}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::_Node = std::_List_node<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:1688:63: required from void std::list<_Tp, _Alloc>::_M_insert(std::list<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {const Foo&}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::iterator = std::_List_iterator<Foo>]
/usr/include/c++/4.9/bits/stl_list.h:1029:9: required from void std::list<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Foo; _Alloc = std::allocator<Foo>; std::list<_Tp, _Alloc>::value_type = Foo]
stackoverflow.cxx:14:30: required from here
/usr/include/c++/4.9/bits/stl_list.h:114:71: error: use of deleted function Foo::Foo(const Foo&)
: __detail::_List_node_base(), _M_data(std::forward<_Args>(__args)...)
^
stackoverflow.cxx:8:3: note: declared here
Foo(const Foo &f) = delete;
^
Upvotes: 3
Views: 367
Reputation: 12299
The push_back
method has two overloads:
void push_back( const T& value );
void push_back( T&& value );
If you use the first one, T
(Foo
in your case) must be "CopyInsertable". If you use the second one, it must be "MoveInsertable".
Your passFoo2
function receives a const Foo&&
reference, and since it is const
-qualified (see note below), the first overload is the best match. So, that overload is called, which requires your class Foo
to be copyable.
Note: Function std::move
transform a named-object to make it anonymous, and so, suitable to be binded by a rvalue-reference, but it doesn't change const
qualifications (it is a const Foo
anonymous object after the movement). For this reason the first overload is called.
Upvotes: 2
Reputation: 69912
the reason is that push_back has an overload for Foo&&
not const Foo&&
.
const Foo&&
is superfluous. It's a legal type but its existence is an anachronism.
this compiles:
#include <iostream>
#include <list>
class Foo {
public:
Foo() {}
Foo( Foo &&f) noexcept {}
Foo(const Foo &f) = delete;
~Foo() {}
};
void passFoo2(Foo&& f) {
std::list<Foo> list;
list.push_back(std::move(f));
}
int main(int argc, char **argv) {
Foo f;
passFoo2(std::move(f));
return 0;
}
Upvotes: 8