Home | History | Annotate | Download | only in tuple.cnstr
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // UNSUPPORTED: c++98, c++03
     11 
     12 // <tuple>
     13 
     14 // template <class... Types> class tuple;
     15 
     16 // template <class TupleLike>
     17 //   tuple(TupleLike&&);
     18 // template <class Alloc, class TupleLike>
     19 //   tuple(std::allocator_arg_t, Alloc const&, TupleLike&&);
     20 
     21 // Check that the tuple-like ctors are properly disabled when the UTypes...
     22 // constructor should be selected. See PR22806.
     23 
     24 #include <tuple>
     25 #include <memory>
     26 #include <cassert>
     27 
     28 template <class Tp>
     29 using uncvref_t = typename std::remove_cv<typename std::remove_reference<Tp>::type>::type;
     30 
     31 template <class Tuple, class = uncvref_t<Tuple>>
     32 struct IsTuple : std::false_type {};
     33 
     34 template <class Tuple, class ...Args>
     35 struct IsTuple<Tuple, std::tuple<Args...>> : std::true_type {};
     36 
     37 struct ConstructibleFromTupleAndInt {
     38   enum State { FromTuple, FromInt, Copied, Moved };
     39   State state;
     40 
     41   ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt const&) : state(Copied) {}
     42   ConstructibleFromTupleAndInt(ConstructibleFromTupleAndInt &&) : state(Moved) {}
     43 
     44   template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
     45   explicit ConstructibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
     46 
     47   explicit ConstructibleFromTupleAndInt(int) : state(FromInt) {}
     48 };
     49 
     50 struct ConvertibleFromTupleAndInt {
     51   enum State { FromTuple, FromInt, Copied, Moved };
     52   State state;
     53 
     54   ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt const&) : state(Copied) {}
     55   ConvertibleFromTupleAndInt(ConvertibleFromTupleAndInt &&) : state(Moved) {}
     56 
     57   template <class Tuple, class = typename std::enable_if<IsTuple<Tuple>::value>::type>
     58   ConvertibleFromTupleAndInt(Tuple&&) : state(FromTuple) {}
     59 
     60   ConvertibleFromTupleAndInt(int) : state(FromInt) {}
     61 };
     62 
     63 struct ConstructibleFromInt {
     64   enum State { FromInt, Copied, Moved };
     65   State state;
     66 
     67   ConstructibleFromInt(ConstructibleFromInt const&) : state(Copied) {}
     68   ConstructibleFromInt(ConstructibleFromInt &&) : state(Moved) {}
     69 
     70   explicit ConstructibleFromInt(int) : state(FromInt) {}
     71 };
     72 
     73 struct ConvertibleFromInt {
     74   enum State { FromInt, Copied, Moved };
     75   State state;
     76 
     77   ConvertibleFromInt(ConvertibleFromInt const&) : state(Copied) {}
     78   ConvertibleFromInt(ConvertibleFromInt &&) : state(Moved) {}
     79   ConvertibleFromInt(int) : state(FromInt) {}
     80 };
     81 
     82 int main()
     83 {
     84     // Test for the creation of dangling references when a tuple is used to
     85     // store a reference to another tuple as its only element.
     86     // Ex std::tuple<std::tuple<int>&&>.
     87     // In this case the constructors 1) 'tuple(UTypes&&...)'
     88     // and 2) 'tuple(TupleLike&&)' need to be manually disambiguated because
     89     // when both #1 and #2 participate in partial ordering #2 will always
     90     // be chosen over #1.
     91     // See PR22806  and LWG issue #2549 for more information.
     92     // (https://bugs.llvm.org/show_bug.cgi?id=22806)
     93     using T = std::tuple<int>;
     94     std::allocator<int> A;
     95     { // rvalue reference
     96         T t1(42);
     97         std::tuple< T&& > t2(std::move(t1));
     98         assert(&std::get<0>(t2) == &t1);
     99     }
    100     { // const lvalue reference
    101         T t1(42);
    102 
    103         std::tuple< T const & > t2(t1);
    104         assert(&std::get<0>(t2) == &t1);
    105 
    106         std::tuple< T const & > t3(static_cast<T const&>(t1));
    107         assert(&std::get<0>(t3) == &t1);
    108     }
    109     { // lvalue reference
    110         T t1(42);
    111 
    112         std::tuple< T & > t2(t1);
    113         assert(&std::get<0>(t2) == &t1);
    114     }
    115     { // const rvalue reference
    116         T t1(42);
    117 
    118         std::tuple< T const && > t2(std::move(t1));
    119         assert(&std::get<0>(t2) == &t1);
    120     }
    121     { // rvalue reference via uses-allocator
    122         T t1(42);
    123         std::tuple< T&& > t2(std::allocator_arg, A, std::move(t1));
    124         assert(&std::get<0>(t2) == &t1);
    125     }
    126     { // const lvalue reference via uses-allocator
    127         T t1(42);
    128 
    129         std::tuple< T const & > t2(std::allocator_arg, A, t1);
    130         assert(&std::get<0>(t2) == &t1);
    131 
    132         std::tuple< T const & > t3(std::allocator_arg, A, static_cast<T const&>(t1));
    133         assert(&std::get<0>(t3) == &t1);
    134     }
    135     { // lvalue reference via uses-allocator
    136         T t1(42);
    137 
    138         std::tuple< T & > t2(std::allocator_arg, A, t1);
    139         assert(&std::get<0>(t2) == &t1);
    140     }
    141     { // const rvalue reference via uses-allocator
    142         T const t1(42);
    143         std::tuple< T const && > t2(std::allocator_arg, A, std::move(t1));
    144         assert(&std::get<0>(t2) == &t1);
    145     }
    146     // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
    147     // 'tuple<T>' where UDT *can* be constructed from 'tuple<T>'. In this case
    148     // the 'tuple(UTypes...)' ctor should be chosen and 'UDT' constructed from
    149     // 'tuple<T>'.
    150     {
    151         using VT = ConstructibleFromTupleAndInt;
    152         std::tuple<int> t1(42);
    153         std::tuple<VT> t2(t1);
    154         assert(std::get<0>(t2).state == VT::FromTuple);
    155     }
    156     {
    157         using VT = ConvertibleFromTupleAndInt;
    158         std::tuple<int> t1(42);
    159         std::tuple<VT> t2 = {t1};
    160         assert(std::get<0>(t2).state == VT::FromTuple);
    161     }
    162     // Test constructing a 1-tuple of the form tuple<UDT> from another 1-tuple
    163     // 'tuple<T>' where UDT cannot be constructed from 'tuple<T>' but can
    164     // be constructed from 'T'. In this case the tuple-like ctor should be
    165     // chosen and 'UDT' constructed from 'T'
    166     {
    167         using VT = ConstructibleFromInt;
    168         std::tuple<int> t1(42);
    169         std::tuple<VT> t2(t1);
    170         assert(std::get<0>(t2).state == VT::FromInt);
    171     }
    172     {
    173         using VT = ConvertibleFromInt;
    174         std::tuple<int> t1(42);
    175         std::tuple<VT> t2 = {t1};
    176         assert(std::get<0>(t2).state == VT::FromInt);
    177     }
    178 }
    179