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