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