1 // The Art of C++ / Tuple 2 // Copyright (c) 2015-2016 Daniel Frey 3 4 #ifndef TAOCPP_INCLUDE_TUPLE_TUPLE_HPP 5 #define TAOCPP_INCLUDE_TUPLE_TUPLE_HPP 6 7 #include "../seq/config.hpp" 8 #include "../seq/integer_sequence.hpp" 9 #include "../seq/is_all.hpp" 10 #include "../seq/type_by_index.hpp" 11 #include "../seq/sum.hpp" 12 #include "../seq/make_integer_sequence.hpp" 13 #include "../seq/inclusive_scan.hpp" 14 #include "../seq/minus.hpp" 15 #include "../seq/map.hpp" 16 #include "../seq/exclusive_scan.hpp" 17 18 #include <type_traits> 19 #include <utility> 20 #include <memory> 21 22 #if (__cplusplus >= 201402L) 23 #define TAOCPP_TUPLE_CONSTEXPR constexpr 24 #else 25 #define TAOCPP_TUPLE_CONSTEXPR 26 #endif 27 28 namespace tao 29 { 30 template< typename... Ts > 31 struct tuple; 32 } 33 34 namespace std 35 { 36 // 20.4.2.8 Tuple traits [tuple.traits] 37 38 template< typename... Ts, typename A > 39 struct uses_allocator< tao::tuple< Ts... >, A > : true_type {}; 40 } 41 42 namespace tao 43 { 44 template< std::size_t I, typename... Ts > 45 TAOCPP_TUPLE_CONSTEXPR 46 const seq::type_by_index_t< I, Ts... >& get( const tuple< Ts... >& ) noexcept; 47 48 template< std::size_t I, typename... Ts > 49 TAOCPP_TUPLE_CONSTEXPR 50 seq::type_by_index_t< I, Ts... >& get( tuple< Ts... >& ) noexcept; 51 52 template< std::size_t I, typename... Ts > 53 TAOCPP_TUPLE_CONSTEXPR 54 seq::type_by_index_t< I, Ts... >&& get( const tuple< Ts... >&& ) noexcept; 55 56 namespace impl 57 { 58 // TODO: std::pair support 59 // TODO: allocator support 60 61 using swallow = bool[]; 62 63 template< typename T, typename > 64 struct dependent_type : T {}; 65 66 template< bool B, typename T = void > 67 using enable_if_t = typename std::enable_if< B, T >::type; 68 69 // TODO: using std::swap? 70 template< typename T > 71 using is_nothrow_swappable = std::integral_constant< bool, noexcept( swap( std::declval< T& >(), std::declval< T& >() ) ) >; 72 73 #if __cplusplus >= 201402L 74 template< typename T > 75 using is_final = std::is_final< T >; 76 #else 77 template< typename T > 78 using is_final = std::integral_constant< bool, __is_final( T ) >; 79 #endif 80 81 template< bool, bool > 82 struct uses_alloc_ctor; 83 84 template< typename T, typename A, typename... As > 85 using uses_alloc_ctor_t = uses_alloc_ctor< std::uses_allocator< T, A >::value, std::is_constructible< T, std::allocator_arg_t, A, As... >::value >*; 86 87 template< std::size_t I, typename T, bool = std::is_empty< T >::value && !is_final< T >::value > 88 struct tuple_value 89 { 90 T value; 91 tuple_valuetao::impl::tuple_value92 constexpr tuple_value() 93 noexcept( std::is_nothrow_default_constructible< T >::value ) 94 : value() 95 { 96 static_assert( !std::is_reference< T >::value, "attempted to default construct a reference element in a tuple" ); 97 } 98 99 template< bool B, typename A > tuple_valuetao::impl::tuple_value100 tuple_value( uses_alloc_ctor< false, B >*, const A& ) 101 : value() 102 { 103 static_assert( !std::is_reference< T >::value, "attempted to default construct a reference element in a tuple" ); 104 } 105 106 template< typename A > tuple_valuetao::impl::tuple_value107 tuple_value( uses_alloc_ctor< true, true >*, const A& a ) 108 : value( std::allocator_arg_t(), a ) 109 { 110 static_assert( !std::is_reference< T >::value, "attempted to default construct a reference element in a tuple" ); 111 } 112 113 template< typename A > tuple_valuetao::impl::tuple_value114 tuple_value( uses_alloc_ctor< true, false >*, const A& a ) 115 : value( a ) 116 { 117 static_assert( !std::is_reference< T >::value, "attempted to default construct a reference element in a tuple" ); 118 } 119 120 template< typename U, 121 typename = impl::enable_if_t< !std::is_same< typename std::decay< U >::type, tuple_value >::value >, 122 typename = impl::enable_if_t< std::is_constructible< T, U >::value > > 123 TAOCPP_TUPLE_CONSTEXPR tuple_valuetao::impl::tuple_value124 explicit tuple_value( U&& v ) 125 noexcept( std::is_nothrow_constructible< T, U >::value ) 126 : value( std::forward< U >( v ) ) 127 {} 128 129 template< bool B, typename A, typename U > tuple_valuetao::impl::tuple_value130 tuple_value( uses_alloc_ctor< false, B >*, const A&, U&& v ) 131 : value( std::forward< U >( v ) ) 132 { 133 // TODO: Add check for rvalue to lvalue reference 134 } 135 136 template< typename A, typename U > tuple_valuetao::impl::tuple_value137 tuple_value( uses_alloc_ctor< true, true >*, const A& a, U&& v ) 138 : value( std::allocator_arg_t(), a, std::forward< U >( v ) ) 139 { 140 // TODO: Add check for rvalue to lvalue reference 141 } 142 143 template< typename A, typename U > tuple_valuetao::impl::tuple_value144 tuple_value( uses_alloc_ctor< true, false >*, const A& a, U&& v ) 145 : value( std::forward< U >( v ), a ) 146 { 147 // TODO: Add check for rvalue to lvalue reference 148 } 149 150 tuple_value( const tuple_value& ) = default; 151 tuple_value( tuple_value&& ) = default; 152 153 template< typename U > operator =tao::impl::tuple_value154 tuple_value& operator=( U&& v ) 155 noexcept( std::is_nothrow_assignable< T&, U >::value ) 156 { 157 value = std::forward< U >( v ); 158 return *this; 159 } 160 swaptao::impl::tuple_value161 void swap( tuple_value& v ) 162 noexcept( is_nothrow_swappable< T >::value ) 163 { 164 using std::swap; 165 swap( value, v.value ); 166 } 167 168 TAOCPP_TUPLE_CONSTEXPR gettao::impl::tuple_value169 T& get() noexcept 170 { 171 return value; 172 } 173 174 TAOCPP_TUPLE_CONSTEXPR gettao::impl::tuple_value175 const T& get() const noexcept 176 { 177 return value; 178 } 179 }; 180 181 template< std::size_t I, typename T > 182 struct tuple_value< I, T, true > 183 : private T 184 { tuple_valuetao::impl::tuple_value185 constexpr tuple_value() 186 noexcept( std::is_nothrow_default_constructible< T >::value ) 187 : T() 188 {} 189 190 template< bool B, typename A > tuple_valuetao::impl::tuple_value191 tuple_value( uses_alloc_ctor< false, B >*, const A& ) 192 : T() 193 {} 194 195 template< typename A > tuple_valuetao::impl::tuple_value196 tuple_value( uses_alloc_ctor< true, true >*, const A& a ) 197 : T( std::allocator_arg_t(), a ) 198 {} 199 200 template< typename A > tuple_valuetao::impl::tuple_value201 tuple_value( uses_alloc_ctor< true, false >*, const A& a ) 202 : T( a ) 203 {} 204 205 template< typename U, 206 typename = impl::enable_if_t< !std::is_same< typename std::decay< U >::type, tuple_value >::value >, 207 typename = impl::enable_if_t< std::is_constructible< T, U >::value > > 208 TAOCPP_TUPLE_CONSTEXPR tuple_valuetao::impl::tuple_value209 explicit tuple_value( U&& v ) 210 noexcept( std::is_nothrow_constructible< T, U >::value ) 211 : T( std::forward< U >( v ) ) 212 {} 213 214 template< bool B, typename A, typename U > tuple_valuetao::impl::tuple_value215 tuple_value( uses_alloc_ctor< false, B >*, const A&, U&& v ) 216 : T( std::forward< U >( v ) ) 217 {} 218 219 template< typename A, typename U > tuple_valuetao::impl::tuple_value220 tuple_value( uses_alloc_ctor< true, true >*, const A& a, U&& v ) 221 : T( std::allocator_arg_t(), a, std::forward< U >( v ) ) 222 {} 223 224 template< typename A, typename U > tuple_valuetao::impl::tuple_value225 tuple_value( uses_alloc_ctor< true, false >*, const A& a, U&& v ) 226 : T( std::forward< U >( v ), a ) 227 {} 228 229 tuple_value( const tuple_value& ) = default; 230 tuple_value( tuple_value&& ) = default; 231 232 template< typename U > operator =tao::impl::tuple_value233 tuple_value& operator=( U&& v ) 234 noexcept( std::is_nothrow_assignable< T&, U >::value ) 235 { 236 T::operator=( std::forward< U >( v ) ); 237 return *this; 238 } 239 swaptao::impl::tuple_value240 void swap( tuple_value& v ) 241 noexcept( is_nothrow_swappable< T >::value ) 242 { 243 using std::swap; 244 swap( *this, v ); 245 } 246 247 TAOCPP_TUPLE_CONSTEXPR gettao::impl::tuple_value248 T& get() noexcept 249 { 250 return static_cast< T& >( *this ); 251 } 252 253 TAOCPP_TUPLE_CONSTEXPR gettao::impl::tuple_value254 const T& get() const noexcept 255 { 256 return static_cast< const T& >( *this ); 257 } 258 }; 259 260 template< typename, typename... > 261 struct tuple_base; 262 263 template< std::size_t... Is, typename... Ts > 264 struct tuple_base< seq::index_sequence< Is... >, Ts... > 265 : tuple_value< Is, Ts >... 266 { 267 constexpr tuple_base() = default; 268 269 template< typename... Us > 270 TAOCPP_TUPLE_CONSTEXPR tuple_basetao::impl::tuple_base271 explicit tuple_base( Us&&... us ) 272 : tuple_value< Is, Ts >( std::forward< Us >( us ) )... 273 {} 274 275 template< typename A, typename... Us > 276 TAOCPP_TUPLE_CONSTEXPR tuple_basetao::impl::tuple_base277 tuple_base( std::allocator_arg_t, const A& a, Us&&... us ) 278 : tuple_value< Is, Ts >( uses_alloc_ctor_t< Ts, A, Us >(), a, std::forward< Us >( us ) )... 279 {} 280 281 tuple_base( const tuple_base& ) = default; 282 tuple_base( tuple_base&& ) = default; 283 operator =tao::impl::tuple_base284 tuple_base& operator=( const tuple_base& v ) 285 noexcept( seq::is_all< std::is_nothrow_copy_assignable< Ts >::value... >::value ) 286 { 287 #ifdef TAOCPP_FOLD_EXPRESSIONS 288 ( tuple_value< Is, Ts >::operator=( static_cast< tuple_value< Is, Ts >& >( v ).get() ), ... ); 289 #else 290 (void)swallow{ ( tuple_value< Is, Ts >::operator=( static_cast< tuple_value< Is, Ts >& >( v ).get() ), true )..., true }; 291 #endif 292 return *this; 293 } 294 operator =tao::impl::tuple_base295 tuple_base& operator=( tuple_base&& v ) 296 noexcept( seq::is_all< std::is_nothrow_move_assignable< Ts >::value... >::value ) 297 { 298 #ifdef TAOCPP_FOLD_EXPRESSIONS 299 ( tuple_value< Is, Ts >::operator=( std::forward< Ts >( static_cast< tuple_value< Is, Ts >& >( v ).get() ) ), ... ); 300 #else 301 (void)swallow{ ( tuple_value< Is, Ts >::operator=( static_cast< tuple_value< Is, Ts >& >( v ) ), true )..., true }; 302 #endif 303 return *this; 304 } 305 306 template< typename... Us > operator =tao::impl::tuple_base307 tuple_base& operator=( const tuple< Us... >& v ) 308 noexcept( seq::is_all< std::is_nothrow_assignable< Ts&, const Us& >::value... >::value ) 309 { 310 #ifdef TAOCPP_FOLD_EXPRESSIONS 311 ( tuple_value< Is, Ts >::operator=( get< Is >( v ) ), ... ); 312 #else 313 (void)swallow{ ( tuple_value< Is, Ts >::operator=( get< Is >( v ) ), true )..., true }; 314 #endif 315 return *this; 316 } 317 318 template< typename... Us > operator =tao::impl::tuple_base319 tuple_base& operator=( tuple< Us... >&& v ) 320 noexcept( seq::is_all< std::is_nothrow_assignable< Ts&, Us&& >::value... >::value ) 321 { 322 #ifdef TAOCPP_FOLD_EXPRESSIONS 323 ( tuple_value< Is, Ts >::operator=( get< Is >( std::move( v ) ) ), ... ); 324 #else 325 (void)swallow{ ( tuple_value< Is, Ts >::operator=( get< Is >( std::move( v ) ) ), true )..., true }; 326 #endif 327 return *this; 328 } 329 swaptao::impl::tuple_base330 void swap( tuple_base& v ) 331 noexcept( seq::is_all< impl::is_nothrow_swappable< Ts >::value... >::value ) 332 { 333 #ifdef TAOCPP_FOLD_EXPRESSIONS 334 ( static_cast< tuple_value< Is, Ts >& >( *this ).swap( static_cast< tuple_value< Is, Ts >& >( v ) ), ... ); 335 #else 336 (void)swallow{ ( static_cast< tuple_value< Is, Ts >& >( *this ).swap( static_cast< tuple_value< Is, Ts >& >( v ) ), true )..., true }; 337 #endif 338 } 339 }; 340 } 341 342 // 20.4.2 Class template tuple [tuple.tuple] 343 344 // tuple 345 template< typename... Ts > 346 struct tuple 347 { 348 private: 349 using base_t = impl::tuple_base< seq::index_sequence_for< Ts... >, Ts... >; 350 base_t base; 351 352 template< std::size_t I, typename... Us > 353 friend TAOCPP_TUPLE_CONSTEXPR 354 const seq::type_by_index_t< I, Us... >& get( const tuple< Us... >& ) noexcept; 355 356 template< std::size_t I, typename... Us > 357 friend TAOCPP_TUPLE_CONSTEXPR 358 seq::type_by_index_t< I, Us... >& get( tuple< Us... >& ) noexcept; 359 360 template< std::size_t I, typename... Us > 361 friend TAOCPP_TUPLE_CONSTEXPR 362 seq::type_by_index_t< I, Us... >&& get( tuple< Us... >&& ) noexcept; 363 364 public: 365 // 20.4.2.1 Construction [tuple.cnstr] 366 367 // TODO: Move this templated condition to base? 368 template< typename dummy = void, 369 typename = impl::enable_if_t< seq::is_all< impl::dependent_type< std::is_default_constructible< Ts >, dummy >::value... >::value > > tupletao::tuple370 constexpr tuple() 371 noexcept( seq::is_all< std::is_nothrow_default_constructible< Ts >::value... >::value ) 372 : base() 373 {} 374 375 template< typename dummy = void, 376 typename = impl::enable_if_t< seq::is_all< impl::dependent_type< std::is_copy_constructible< Ts >, dummy >::value... >::value > > 377 TAOCPP_TUPLE_CONSTEXPR tupletao::tuple378 explicit tuple( const Ts&... ts ) 379 noexcept( seq::is_all< std::is_nothrow_copy_constructible< Ts >::value... >::value ) 380 : base( ts... ) 381 {} 382 383 template< typename... Us, 384 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 385 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, Us&& >::value... >::value > > 386 TAOCPP_TUPLE_CONSTEXPR tupletao::tuple387 explicit tuple( Us&&... us ) 388 noexcept( seq::is_all< std::is_nothrow_constructible< Ts, Us&& >::value... >::value ) 389 : base( std::forward< Us >( us )... ) 390 {} 391 392 tuple( const tuple& ) = default; 393 tuple( tuple&& ) = default; 394 395 template< typename... Us, 396 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 397 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, const Us& >::value... >::value > > 398 TAOCPP_TUPLE_CONSTEXPR tupletao::tuple399 explicit tuple( const tuple< Us... >& v ) 400 noexcept( seq::is_all< std::is_nothrow_constructible< Ts, const Us& >::value... >::value ) 401 : base( v ) 402 {} 403 404 template< typename... Us, 405 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 406 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, Us&& >::value... >::value > > 407 TAOCPP_TUPLE_CONSTEXPR tupletao::tuple408 explicit tuple( tuple< Us... >&& v ) 409 noexcept( seq::is_all< std::is_nothrow_constructible< Ts, Us&& >::value... >::value ) 410 : base( std::move( v ) ) 411 {} 412 413 template< typename A, 414 typename dummy = void, 415 typename = impl::enable_if_t< seq::is_all< impl::dependent_type< std::is_default_constructible< Ts >, dummy >::value... >::value > > tupletao::tuple416 tuple( std::allocator_arg_t, const A& a ) 417 : base( std::allocator_arg_t(), a ) 418 {} 419 420 template< typename A, 421 typename dummy = void, 422 typename = impl::enable_if_t< seq::is_all< impl::dependent_type< std::is_copy_constructible< Ts >, dummy >::value... >::value > > tupletao::tuple423 tuple( std::allocator_arg_t, const A& a, const Ts&... ts ) 424 : base( std::allocator_arg_t(), a, ts... ) 425 {} 426 427 template< typename A, 428 typename... Us, 429 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 430 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, Us&& >::value... >::value > > tupletao::tuple431 tuple( std::allocator_arg_t, const A& a, Us&&... us ) 432 : base( std::allocator_arg_t(), a, std::forward< Us >( us )... ) 433 {} 434 435 template< typename A > tupletao::tuple436 tuple( std::allocator_arg_t, const A& a, const tuple& v ) 437 : base( std::allocator_arg_t(), a, v ) 438 {} 439 440 template< typename A > tupletao::tuple441 tuple( std::allocator_arg_t, const A& a, tuple&& v ) 442 : base( std::allocator_arg_t(), a, std::move( v ) ) 443 {} 444 445 template< typename A, 446 typename... Us, 447 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 448 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, const Us& >::value... >::value > > tupletao::tuple449 tuple( std::allocator_arg_t, const A& a, const tuple< Us... >& v ) 450 : base( std::allocator_arg_t(), a, v ) 451 {} 452 453 template< typename A, 454 typename... Us, 455 typename = impl::enable_if_t< sizeof...( Us ) == sizeof...( Ts ) >, 456 typename = impl::enable_if_t< seq::is_all< std::is_constructible< Ts, Us&& >::value... >::value > > tupletao::tuple457 tuple( std::allocator_arg_t, const A& a, tuple< Us... >&& v ) 458 : base( std::allocator_arg_t(), a, std::move( v ) ) 459 {} 460 461 // 20.4.2.2 Assignment [tuple.assign] 462 463 template< typename T, 464 typename = impl::enable_if_t< std::is_assignable< base_t&, T >::value > > operator =tao::tuple465 tuple& operator=( T&& v ) 466 noexcept( std::is_nothrow_assignable< base_t&, T >::value ) 467 { 468 base = std::forward< T >( v ); 469 return *this; 470 } 471 472 // 20.4.2.3 swap [tuple.swap] 473 swaptao::tuple474 void swap( tuple& v ) 475 noexcept( noexcept( base.swap( v.base ) ) ) 476 { 477 base.swap( v.base ); 478 } 479 }; 480 481 template<> 482 struct tuple<> 483 { tupletao::tuple484 constexpr tuple() noexcept {} tupletao::tuple485 template< typename A > tuple( std::allocator_arg_t, const A& ) noexcept {} tupletao::tuple486 template< typename A > tuple( std::allocator_arg_t, const A&, const tuple& ) noexcept {} swaptao::tuple487 void swap( tuple& ) noexcept {} 488 }; 489 490 // 20.4.2.4 Tuple creation functions [tuple.creation] 491 492 // ignore helper 493 namespace impl 494 { 495 struct ignore_t 496 { 497 template< typename U > operator =tao::impl::ignore_t498 ignore_t& operator=( U&& ) 499 { 500 return *this; 501 } 502 }; 503 } 504 505 // ignore 506 const impl::ignore_t ignore{}; 507 508 // make_tuple helper 509 namespace impl 510 { 511 template< typename T > 512 struct make_tuple_return 513 { 514 using type = T; 515 }; 516 517 template< typename T > 518 struct make_tuple_return< std::reference_wrapper< T > > 519 { 520 using type = T&; 521 }; 522 523 template< typename T > 524 using make_tuple_return_t = typename make_tuple_return< T >::type; 525 } 526 527 // make_tuple 528 template< typename... Ts, typename R = tuple< impl::make_tuple_return_t< typename std::decay< Ts >::type >... > > 529 TAOCPP_TUPLE_CONSTEXPR make_tuple(Ts &&...ts)530 R make_tuple( Ts&&... ts ) 531 { 532 return R( std::forward< Ts >( ts )... ); 533 } 534 535 // forward_as_tuple 536 template< typename... Ts > 537 TAOCPP_TUPLE_CONSTEXPR forward_as_tuple(Ts &&...ts)538 tuple< Ts&&... > forward_as_tuple( Ts&&... ts ) noexcept 539 { 540 return tuple< Ts&&... >( std::forward< Ts >( ts )... ); 541 } 542 543 // tie 544 template< typename... Ts > 545 TAOCPP_TUPLE_CONSTEXPR tie(Ts &...ts)546 tuple< Ts&... > tie( Ts&... ts ) noexcept 547 { 548 return tuple< Ts&... >( ts... ); 549 } 550 551 // tuple_cat is found at the end, as it requires access to tuple_element_t and get<I> 552 553 // 20.4.2.5 Tuple helper classes [tuple.helper] 554 555 // tuple_size 556 template< typename T > struct tuple_size; 557 template< typename T > struct tuple_size< const T > : tuple_size< T > {}; 558 template< typename T > struct tuple_size< volatile T > : tuple_size< T > {}; 559 template< typename T > struct tuple_size< const volatile T > : tuple_size< T > {}; 560 561 template< typename... Ts > 562 struct tuple_size< tuple< Ts... > > 563 : std::integral_constant< std::size_t, sizeof...( Ts ) > 564 {}; 565 566 // tuple_element 567 template< std::size_t I, typename T > struct tuple_element; 568 template< std::size_t I, typename T > struct tuple_element< I, const T > : tuple_element< I, T > {}; 569 template< std::size_t I, typename T > struct tuple_element< I, volatile T > : tuple_element< I, T > {}; 570 template< std::size_t I, typename T > struct tuple_element< I, const volatile T > : tuple_element< I, T > {}; 571 572 template< std::size_t I, typename... Ts > 573 struct tuple_element< I, tuple< Ts... > > 574 : seq::type_by_index< I, Ts... > 575 {}; 576 577 #if __cplusplus >= 201402L 578 template< std::size_t I, typename T > 579 using tuple_element_t = typename tuple_element< I, T >::type; 580 #endif 581 582 // 20.4.2.6 Element access [tuple.elem] 583 584 // get<I> 585 template< std::size_t I, typename... Ts > 586 TAOCPP_TUPLE_CONSTEXPR get(const tuple<Ts...> & v)587 const seq::type_by_index_t< I, Ts... >& get( const tuple< Ts... >& v ) noexcept 588 { 589 return static_cast< const impl::tuple_value< I, seq::type_by_index_t< I, Ts... > >& >( v.base ).get(); 590 } 591 592 template< std::size_t I, typename... Ts > 593 TAOCPP_TUPLE_CONSTEXPR get(tuple<Ts...> & v)594 seq::type_by_index_t< I, Ts... >& get( tuple< Ts... >& v ) noexcept 595 { 596 return static_cast< impl::tuple_value< I, seq::type_by_index_t< I, Ts... > >& >( v.base ).get(); 597 } 598 599 template< std::size_t I, typename... Ts > 600 TAOCPP_TUPLE_CONSTEXPR get(tuple<Ts...> && v)601 seq::type_by_index_t< I, Ts... >&& get( tuple< Ts... >&& v ) noexcept 602 { 603 using type = seq::type_by_index_t< I, Ts... >; 604 return static_cast< type&& >( static_cast< impl::tuple_value< I, type >& >( v.base ).get() ); 605 } 606 607 // get<T> helper 608 namespace impl 609 { 610 template< typename T, typename... Ts > 611 using count_of = seq::sum< std::size_t, ( std::is_same< T, Ts >::value ? 1 : 0 )... >; 612 613 template< typename, typename, typename... > 614 struct index_of_impl; 615 616 template< std::size_t... Is, typename T, typename... Ts > 617 struct index_of_impl< seq::index_sequence< Is... >, T, Ts... > 618 : seq::sum< std::size_t, ( std::is_same< T, Ts >::value ? Is : 0 )... > 619 { 620 static_assert( count_of< T, Ts... >::value > 0, "T not found within Ts..." ); 621 static_assert( count_of< T, Ts... >::value < 2, "T must be unique within Ts..." ); 622 }; 623 624 template< typename T, typename... Ts > 625 using index_of = index_of_impl< seq::index_sequence_for< Ts... >, T, Ts... >; 626 } 627 628 // get<T> 629 template< typename T, typename... Ts > 630 TAOCPP_TUPLE_CONSTEXPR get(const tuple<Ts...> & v)631 const T& get( const tuple< Ts... >& v ) noexcept 632 { 633 return get< impl::index_of< T, Ts... >::value >( v ); 634 } 635 636 template< typename T, typename... Ts > 637 TAOCPP_TUPLE_CONSTEXPR get(tuple<Ts...> & v)638 T& get( tuple< Ts... >& v ) noexcept 639 { 640 return get< impl::index_of< T, Ts... >::value >( v ); 641 } 642 643 template< typename T, typename... Ts > 644 TAOCPP_TUPLE_CONSTEXPR get(tuple<Ts...> && v)645 T&& get( tuple< Ts... >&& v ) noexcept 646 { 647 return get< impl::index_of< T, Ts... >::value >( std::move( v ) ); 648 } 649 650 // 20.4.2.7 Relational operators [tuple.rel] 651 652 // operators helper 653 namespace impl 654 { 655 template< typename > 656 struct tuple_equal; 657 658 template< std::size_t... Is > 659 struct tuple_equal< seq::index_sequence< Is... > > 660 { 661 template< typename T, typename U > 662 TAOCPP_TUPLE_CONSTEXPR operator ()tao::impl::tuple_equal663 bool operator()( const T& lhs, const U& rhs ) const 664 { 665 #ifdef TAOCPP_FOLD_EXPRESSIONS 666 return ( static_cast< bool >( get< Is >( lhs ) == get< Is >( rhs ) ) && ... ); 667 #else 668 bool result = true; 669 (void)swallow{ ( result = result && static_cast< bool >( get< Is >( lhs ) == get< Is >( rhs ) ) )..., true }; 670 return result; 671 #endif 672 } 673 }; 674 675 template< typename > 676 struct tuple_less; 677 678 template< std::size_t... Is > 679 struct tuple_less< seq::index_sequence< Is... > > 680 { 681 template< typename T, typename U > 682 TAOCPP_TUPLE_CONSTEXPR operator ()tao::impl::tuple_less683 bool operator()( const T& lhs, const U& rhs ) const 684 { 685 bool result = false; 686 #ifdef TAOCPP_DUMMY // TAOCPP_FOLD_EXPRESSIONS 687 // TODO: This fold expression does not work as expected. Why? 688 (void)( ( ( result = static_cast< bool >( get< Is >( lhs ) < get< Is >( rhs ) ) ) || static_cast< bool >( get< Is >( rhs ) < get< Is >( lhs ) ) ) || ... ); 689 #else 690 bool no_result_yet = false; 691 (void)swallow{ ( no_result_yet = no_result_yet || ( result = static_cast< bool >( get< Is >( lhs ) < get< Is >( rhs ) ) ) || static_cast< bool >( get< Is >( rhs ) < get< Is >( lhs ) ) )..., true }; 692 (void)no_result_yet; 693 #endif 694 return result; 695 } 696 }; 697 } 698 699 // operators 700 template< typename... Ts, typename... Us, typename = impl::enable_if_t< sizeof...( Ts ) == sizeof...( Us ) > > 701 TAOCPP_TUPLE_CONSTEXPR operator ==(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)702 bool operator==( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 703 { 704 return impl::tuple_equal< seq::index_sequence_for< Ts... > >()( lhs, rhs ); 705 } 706 707 template< typename... Ts, typename... Us > 708 TAOCPP_TUPLE_CONSTEXPR operator !=(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)709 bool operator!=( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 710 { 711 return !( lhs == rhs ); 712 } 713 714 template< typename... Ts, typename... Us, typename = impl::enable_if_t< sizeof...( Ts ) == sizeof...( Us ) > > 715 TAOCPP_TUPLE_CONSTEXPR operator <(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)716 bool operator<( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 717 { 718 return impl::tuple_less< seq::index_sequence_for< Ts... > >()( lhs, rhs ); 719 } 720 721 template< typename... Ts, typename... Us > 722 TAOCPP_TUPLE_CONSTEXPR operator >=(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)723 bool operator>=( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 724 { 725 return !( lhs < rhs ); 726 } 727 728 template< typename... Ts, typename... Us > 729 TAOCPP_TUPLE_CONSTEXPR operator >(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)730 bool operator>( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 731 { 732 return rhs < lhs; 733 } 734 735 template< typename... Ts, typename... Us > 736 TAOCPP_TUPLE_CONSTEXPR operator <=(const tuple<Ts...> & lhs,const tuple<Us...> & rhs)737 bool operator<=( const tuple< Ts... >& lhs, const tuple< Us... >& rhs ) 738 { 739 return !( rhs < lhs ); 740 } 741 742 // 20.4.2.9 Tuple specialized algorithms [tuple.special] 743 744 // swap 745 template< typename... Ts > swap(tuple<Ts...> & lhs,tuple<Ts...> & rhs)746 void swap( tuple< Ts... >& lhs, tuple< Ts... >& rhs ) 747 noexcept( noexcept( lhs.swap( rhs ) ) ) 748 { 749 lhs.swap( rhs ); 750 } 751 752 // (continued:) 20.4.2.4 Tuple creation functions [tuple.creation] 753 754 // tuple_cat helper 755 namespace impl 756 { 757 template< std::size_t M, std::size_t... Ns > 758 struct count_less_or_equal 759 : seq::sum< std::size_t, ( ( Ns <= M ) ? 1 : 0 )... > 760 {}; 761 762 template< typename, typename > 763 struct expand; 764 765 template< std::size_t... Is, std::size_t... Ns > 766 struct expand< seq::index_sequence< Is... >, seq::index_sequence< Ns... > > 767 { 768 using type = seq::index_sequence< count_less_or_equal< Is, Ns... >::value... >; 769 }; 770 771 template< typename I, typename S > 772 using expand_t = typename expand< I, S >::type; 773 774 template< typename... > 775 struct tuple_cat_result; 776 777 template< std::size_t... Os, std::size_t... Is, typename... Ts > 778 struct tuple_cat_result< seq::index_sequence< Os... >, seq::index_sequence< Is... >, Ts... > 779 { 780 using type = tuple< typename tuple_element< Is, seq::type_by_index_t< Os, Ts... > >::type... >; 781 }; 782 783 template< typename... Ts > 784 using tuple_cat_result_t = typename tuple_cat_result< Ts... >::type; 785 786 template< typename... Ts > 787 struct tuple_cat_helper 788 { 789 using tuple_size_sequence = seq::index_sequence< tuple_size< Ts >::value... >; 790 using result_index_sequence = seq::make_index_sequence< seq::sum< tuple_size_sequence >::value >; 791 792 using outer_index_sequence = expand_t< result_index_sequence, seq::inclusive_scan_t< tuple_size_sequence > >; 793 using inner_index_sequence = seq::minus_t< result_index_sequence, seq::map_t< outer_index_sequence, seq::exclusive_scan_t< tuple_size_sequence > > >; 794 795 using result_type = tuple_cat_result_t< outer_index_sequence, inner_index_sequence, Ts... >; 796 }; 797 798 template< typename R, std::size_t... Os, std::size_t... Is, typename T > 799 TAOCPP_TUPLE_CONSTEXPR tuple_cat(seq::index_sequence<Os...>,seq::index_sequence<Is...>,T v)800 R tuple_cat( seq::index_sequence< Os... >, seq::index_sequence< Is... >, T v ) 801 { 802 return R( get< Is >( get< Os >( v ) )... ); 803 } 804 } 805 806 // tuple_cat 807 template< typename... Ts, typename H = impl::tuple_cat_helper< typename std::remove_reference< Ts >::type... >, typename R = typename H::result_type > 808 TAOCPP_TUPLE_CONSTEXPR tuple_cat(Ts &&...ts)809 R tuple_cat( Ts&&... ts ) 810 { 811 return impl::tuple_cat< R >( typename H::outer_index_sequence(), typename H::inner_index_sequence(), tao::forward_as_tuple( std::forward< Ts >( ts )... ) ); 812 } 813 } 814 815 #undef TAOCPP_TUPLE_CONSTEXPR 816 817 #endif // TAOCPP_INCLUDE_TUPLE_TUPLE_HPP 818