This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libstdc++/41530] New: [c++0x] Cannot move-construct std::tuple from a different type of std::tuple


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]