This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/41530] New: [c++0x] Cannot move-construct std::tuple from a different type of std::tuple
- From: "jbytheway at gmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 30 Sep 2009 21:54:43 -0000
- Subject: [Bug libstdc++/41530] New: [c++0x] Cannot move-construct std::tuple from a different type of std::tuple
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
Consider the following:
=====
#include <tuple>
class A {};
class B : public A {};
int main()
{
std::tuple<B*> b;
std::tuple<A*> a1(b); // Compiles fine
std::tuple<A*> a2(std::move(b)); // Error
return 0;
}
=====
Copy constructing a std::tuple<A*> from a std::tuple<B*> works fine, but
move-constructing it doesn't, but I believe it should (according to
[tuple.cnstr] p6). It generates the following error:
In file included from tuple.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/include/g++-v4/tuple: In constructor
?std::_Head_base<_Idx, _Head, false>::_Head_base(_UHead&&) [with _UHead =
std::_Head_base<0ul, B*, false>, long unsigned int _Idx = 0ul, _Head = A*]?:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/include/g++-v4/tuple:179: instantiated
from ?std::_Tuple_impl<_Idx, _Head, _Tail
...>::_Tuple_impl(std::_Tuple_impl<_Idx, _UElements ...>&&) [with _UElements =
B*, long unsigned int _Idx = 0ul, _Head = A*, _Tail = ]?
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/include/g++-v4/tuple:256: instantiated
from ?std::tuple<_Elements>::tuple(std::tuple<_UElements ...>&&) [with
_UElements = B*, _Elements = A*]?
tuple.cpp:10: instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/include/g++-v4/tuple:94: error: cannot
convert ?std::_Head_base<0ul, B*, false>? to ?A*? in initialization
Looking at the header <tuple>, I believe the problem is in the _Tuple_impl move
constructor lines 174--179:
template<typename... _UElements>
_Tuple_impl(_Tuple_impl<_Idx, _UElements...>&& __in)
: _Inherited(std::move<typename _Tuple_impl<_Idx, _UElements...>::
_Inherited&&>(__in._M_tail())),
_Base(std::forward<typename _Tuple_impl<_Idx, _UElements...>::
_Base>(__in._M_head())) { }
The second initialiser is passing the wrong type to std::forward. _Base (which
is _Head_base<0, A*, false>) expects to be given an A*, and should be being
given a B* which will convert to an A*, but in fact it's being given a
_Head_base<0, B*, false>. There's no obvious way to access the type that needs
to be given to std::forward (i.e. B*), but that's OK, because I don't think it
should be using std::forward anyway. __in._M_head() will always return an
lvalue reference, so the use of std::forward is pointless; it should be
std::move. I believe the following is correct:
template<typename... _UElements>
_Tuple_impl(_Tuple_impl<_Idx, _UElements...>&& __in)
: _Inherited(std::move<typename _Tuple_impl<_Idx, _UElements...>::
_Inherited&&>(__in._M_tail())),
_Base(std::move(__in._M_head())) { }
Here's a patch on svn HEAD:
Index: libstdc++-v3/include/std/tuple
===================================================================
--- libstdc++-v3/include/std/tuple (revision 152346)
+++ libstdc++-v3/include/std/tuple (working copy)
@@ -174,8 +174,7 @@
template<typename... _UElements>
_Tuple_impl(_Tuple_impl<_Idx, _UElements...>&& __in)
: _Inherited(std::move(__in._M_tail())),
- _Base(std::forward<typename _Tuple_impl<_Idx, _UElements...>::
- _Base>(__in._M_head())) { }
+ _Base(std::move(__in._M_head())) { }
_Tuple_impl&
operator=(const _Tuple_impl& __in)
--
Summary: [c++0x] Cannot move-construct std::tuple from a
different type of std::tuple
Product: gcc
Version: 4.4.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: jbytheway at gmail dot com
GCC build triplet: x86_64-pc-linux-gnu
GCC host triplet: x86_64-pc-linux-gnu
GCC target triplet: x86_64-pc-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41530