move_convert.pass.cpp (7097B)
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 // <memory> 13 14 // unique_ptr 15 16 // Test unique_ptr converting move ctor 17 18 #include <memory> 19 #include <cassert> 20 21 #include "test_macros.h" 22 #include "type_id.h" 23 #include "unique_ptr_test_helper.h" 24 25 template <int ID = 0> 26 struct GenericDeleter { 27 void operator()(void*) const {} 28 }; 29 30 template <int ID = 0> 31 struct GenericConvertingDeleter { 32 template <int OID> 33 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {} 34 void operator()(void*) const {} 35 }; 36 37 template <class Templ, class Other> 38 struct is_specialization; 39 40 template <template <int> class Templ, int ID1, class Other> 41 struct is_specialization<Templ<ID1>, Other> : std::false_type {}; 42 43 template <template <int> class Templ, int ID1, int ID2> 44 struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {}; 45 46 template <class Templ, class Other> 47 using EnableIfSpecialization = typename std::enable_if< 48 is_specialization<Templ, typename std::decay<Other>::type >::value 49 >::type; 50 51 52 template <int ID> 53 struct TrackingDeleter { 54 TrackingDeleter() : arg_type(&makeArgumentID<>()) {} 55 56 TrackingDeleter(TrackingDeleter const&) 57 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {} 58 59 TrackingDeleter(TrackingDeleter&&) 60 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {} 61 62 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > 63 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {} 64 65 TrackingDeleter& operator=(TrackingDeleter const&) { 66 arg_type = &makeArgumentID<TrackingDeleter const&>(); 67 return *this; 68 } 69 70 TrackingDeleter& operator=(TrackingDeleter &&) { 71 arg_type = &makeArgumentID<TrackingDeleter &&>(); 72 return *this; 73 } 74 75 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > 76 TrackingDeleter& operator=(T&&) { 77 arg_type = &makeArgumentID<T&&>(); 78 return *this; 79 } 80 81 void operator()(void*) const {} 82 83 public: 84 TypeID const* reset() const { 85 TypeID const* tmp = arg_type; 86 arg_type = nullptr; 87 return tmp; 88 } 89 90 mutable TypeID const* arg_type; 91 }; 92 93 94 template <class ExpectT, int ID> 95 bool checkArg(TrackingDeleter<ID> const& d) { 96 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>(); 97 } 98 99 100 template <bool IsArray> 101 void test_sfinae() { 102 typedef typename std::conditional<IsArray, A[], A>::type VT; 103 104 { // Test that different non-reference deleter types are allowed so long 105 // as they convert to each other. 106 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; 107 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; 108 static_assert(std::is_constructible<U1, U2&&>::value, ""); 109 } 110 { // Test that different non-reference deleter types are disallowed when 111 // they cannot convert. 112 using U1 = std::unique_ptr<VT, GenericDeleter<0> >; 113 using U2 = std::unique_ptr<VT, GenericDeleter<1> >; 114 static_assert(!std::is_constructible<U1, U2&&>::value, ""); 115 } 116 { // Test that if the destination deleter is a reference type then only 117 // exact matches are allowed. 118 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >; 119 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; 120 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; 121 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; 122 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; 123 static_assert(!std::is_constructible<U1, U2&&>::value, ""); 124 static_assert(!std::is_constructible<U1, U3&&>::value, ""); 125 static_assert(!std::is_constructible<U1, U4&&>::value, ""); 126 static_assert(!std::is_constructible<U1, U5&&>::value, ""); 127 128 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>; 129 static_assert(std::is_nothrow_constructible<U1C, U1&&>::value, ""); 130 } 131 { // Test that non-reference destination deleters can be constructed 132 // from any source deleter type with a sutible conversion. Including 133 // reference types. 134 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; 135 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; 136 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>; 137 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; 138 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>; 139 using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; 140 static_assert(std::is_constructible<U1, U2&&>::value, ""); 141 static_assert(std::is_constructible<U1, U3&&>::value, ""); 142 static_assert(std::is_constructible<U1, U4&&>::value, ""); 143 static_assert(std::is_constructible<U1, U5&&>::value, ""); 144 static_assert(std::is_constructible<U1, U6&&>::value, ""); 145 } 146 } 147 148 149 template <bool IsArray> 150 void test_noexcept() { 151 typedef typename std::conditional<IsArray, A[], A>::type VT; 152 { 153 typedef std::unique_ptr<const VT> APtr; 154 typedef std::unique_ptr<VT> BPtr; 155 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); 156 } 157 { 158 typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr; 159 typedef std::unique_ptr<VT, CDeleter<VT> > BPtr; 160 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); 161 } 162 { 163 typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr; 164 typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr; 165 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); 166 } 167 { 168 typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr; 169 typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr; 170 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); 171 } 172 } 173 174 175 template <bool IsArray> 176 void test_deleter_value_category() { 177 typedef typename std::conditional<IsArray, A[], A>::type VT; 178 using TD1 = TrackingDeleter<1>; 179 using TD2 = TrackingDeleter<2>; 180 TD1 d1; 181 TD2 d2; 182 183 { // Test non-reference deleter conversions 184 using U1 = std::unique_ptr<VT, TD1 >; 185 using U2 = std::unique_ptr<VT, TD2 >; 186 U2 u2; 187 u2.get_deleter().reset(); 188 U1 u1(std::move(u2)); 189 assert(checkArg<TD2&&>(u1.get_deleter())); 190 } 191 { // Test assignment from non-const ref 192 using U1 = std::unique_ptr<VT, TD1 >; 193 using U2 = std::unique_ptr<VT, TD2& >; 194 U2 u2(nullptr, d2); 195 U1 u1(std::move(u2)); 196 assert(checkArg<TD2&>(u1.get_deleter())); 197 } 198 { // Test assignment from const ref 199 using U1 = std::unique_ptr<VT, TD1 >; 200 using U2 = std::unique_ptr<VT, TD2 const& >; 201 U2 u2(nullptr, d2); 202 U1 u1(std::move(u2)); 203 assert(checkArg<TD2 const&>(u1.get_deleter())); 204 } 205 } 206 207 208 int main() { 209 { 210 test_sfinae</*IsArray*/false>(); 211 test_noexcept<false>(); 212 test_deleter_value_category<false>(); 213 } 214 { 215 test_sfinae</*IsArray*/true>(); 216 test_noexcept<true>(); 217 test_deleter_value_category<true>(); 218 } 219 }