diff --git a/include/__tuple b/include/__tuple index 72e36fbb..9fc54d47 100644 --- a/include/__tuple +++ b/include/__tuple @@ -68,12 +68,13 @@ template struct _LIBCPP_VISIBLE array; template struct __tuple_like : false_type {}; +template struct __tuple_like : public __tuple_like<_Tp> {}; +template struct __tuple_like : public __tuple_like<_Tp> {}; +template struct __tuple_like : public __tuple_like<_Tp> {}; + template struct __tuple_like> : true_type {}; -template struct __tuple_like> : true_type {}; template struct __tuple_like > : true_type {}; -template struct __tuple_like > : true_type {}; template struct __tuple_like > : true_type {}; -template struct __tuple_like > : true_type {}; template typename tuple_element<_Ip, tuple<_Tp...>>::type& diff --git a/include/tuple b/include/tuple index 27c16ed5..97d21139 100644 --- a/include/tuple +++ b/include/tuple @@ -74,11 +74,8 @@ const unspecified ignore; template tuple make_tuple(T&&...); template tuple forward_as_tuple(T&&...); template tuple tie(T&...); -template tuple tuple_cat(const tuple&, const tuple&); -template tuple tuple_cat(tuple&&, const tuple&); -template tuple tuple_cat(const tuple&, tuple&&); -template tuple tuple_cat(tuple&&, tuple&&); - +template tuple tuple_cat(Tuples&&... tpls); + // 20.4.1.4, tuple helper classes: template class tuple_size; // undefined template class tuple_size>; @@ -751,72 +748,103 @@ operator<=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) // tuple_cat -template -inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -__tuple_cat(const tuple<_Tp...>& __x, __tuple_indices<_I1...>, const tuple<_Up...>& __y, __tuple_indices<_I2...>) +template struct __tuple_cat_type; + +template +struct __tuple_cat_type, __tuple_types<_Utypes...>> { - return tuple<_Tp..., _Up...>(get<_I1>(__x)..., get<_I2>(__y)...); + typedef tuple<_Ttypes..., _Utypes...> type; +}; + +template +struct __tuple_cat_return_1 +{ +}; + +template +struct __tuple_cat_return_1, true, _Tuple0> +{ + typedef typename __tuple_cat_type, + typename __make_tuple_types::type>::type>::type + type; +}; + +template +struct __tuple_cat_return_1, true, _Tuple0, _Tuple1, _Tuples...> + : public __tuple_cat_return_1< + typename __tuple_cat_type< + tuple<_Types...>, + typename __make_tuple_types::type>::type + >::type, + __tuple_like::type>::value, + _Tuple1, _Tuples...> +{ +}; + +template struct __tuple_cat_return; + +template +struct __tuple_cat_return<_Tuple0, _Tuples...> + : public __tuple_cat_return_1, + __tuple_like::type>::value, _Tuple0, + _Tuples...> +{ +}; + +template <> +struct __tuple_cat_return<> +{ + typedef tuple<> type; +}; + +inline _LIBCPP_INLINE_VISIBILITY +tuple<> +tuple_cat() +{ + return tuple<>(); } -template +template inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -tuple_cat(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) +typename __tuple_cat_return<_Tuple>::type +tuple_cat(_Tuple&& __tpl) { - return __tuple_cat(__x, typename __make_tuple_indices::type(), - __y, typename __make_tuple_indices::type()); + typedef typename __tuple_cat_return<_Tuple>::type _R; + return _R(_STD::forward<_Tuple>(__tpl)); } -template +template inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -__tuple_cat(tuple<_Tp...>&& __x, __tuple_indices<_I1...>, const tuple<_Up...>& __y, __tuple_indices<_I2...>) +typename __tuple_cat_return<_Tuple0, _Tuple1>::type +__tuple_cat(_Tuple0&& __t0, __tuple_indices<_I0...>, + _Tuple1&& __t1, __tuple_indices<_I1...>) { - return tuple<_Tp..., _Up...>(_STD::forward<_Tp>(get<_I1>(__x))..., get<_I2>(__y)...); + typedef typename __tuple_cat_return<_Tuple0, _Tuple1>::type _R; + return _R(get<_I0>(_STD::forward<_Tuple0>(__t0))..., + get<_I1>(_STD::forward<_Tuple1>(__t1))...); } -template +template inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -tuple_cat(tuple<_Tp...>&& __x, const tuple<_Up...>& __y) +typename __tuple_cat_return<_Tuple0, _Tuple1>::type +tuple_cat(_Tuple0&& __t0, _Tuple1&& __t1) { - return __tuple_cat(_STD::move(__x), typename __make_tuple_indices::type(), - __y, typename __make_tuple_indices::type()); + typedef typename remove_reference<_Tuple0>::type _T0; + typedef typename remove_reference<_Tuple1>::type _T1; + return __tuple_cat(_STD::forward<_Tuple0>(__t0), + typename __make_tuple_indices::value>::type(), + _STD::forward<_Tuple1>(__t1), + typename __make_tuple_indices::value>::type()); } -template +template inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -__tuple_cat(const tuple<_Tp...>& __x, __tuple_indices<_I1...>, tuple<_Up...>&& __y, __tuple_indices<_I2...>) +typename __tuple_cat_return<_Tuple0, _Tuple1, _Tuples...>::type +tuple_cat(_Tuple0&& __t0, _Tuple1&& __t1, _Tuples&&... __tpls) { - return tuple<_Tp..., _Up...>(get<_I1>(__x)..., _STD::forward<_Up>(get<_I2>(__y))...); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -tuple_cat(const tuple<_Tp...>& __x, tuple<_Up...>&& __y) -{ - return __tuple_cat(__x, typename __make_tuple_indices::type(), - _STD::move(__y), typename __make_tuple_indices::type()); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -__tuple_cat(tuple<_Tp...>&& __x, __tuple_indices<_I1...>, tuple<_Up...>&& __y, __tuple_indices<_I2...>) -{ - return tuple<_Tp..., _Up...>(_STD::forward<_Tp>(get<_I1>(__x))..., _STD::forward<_Up>(get<_I2>(__y))...); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -tuple<_Tp..., _Up...> -tuple_cat(tuple<_Tp...>&& __x, tuple<_Up...>&& __y) -{ - return __tuple_cat(_STD::move(__x), typename __make_tuple_indices::type(), - _STD::move(__y), typename __make_tuple_indices::type()); + return tuple_cat(tuple_cat(_STD::forward<_Tuple0>(__t0), + _STD::forward<_Tuple1>(__t1)), + _STD::forward<_Tuples>(__tpls)...); } template diff --git a/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp b/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp index 7a84c78a..7cfc736f 100644 --- a/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp +++ b/test/utilities/tuple/tuple.tuple/tuple.creation/tuple_cat.pass.cpp @@ -11,23 +11,11 @@ // template class tuple; -// template -// tuple -// tuple_cat(const tuple& t, const tuple& u); -// -// template -// tuple -// tuple_cat(const tuple&& t, const tuple& u); -// -// template -// tuple -// tuple_cat(const tuple& t, const tuple&& u); -// -// template -// tuple -// tuple_cat(const tuple&& t, const tuple&& u); +// template tuple tuple_cat(Tuples&&... tpls); #include +#include +#include #include #include @@ -35,6 +23,43 @@ int main() { + { + std::tuple<> t = std::tuple_cat(); + } + { + std::tuple<> t1; + std::tuple<> t2 = std::tuple_cat(t1); + } + { + std::tuple<> t = std::tuple_cat(std::tuple<>()); + } + { + std::tuple<> t = std::tuple_cat(std::array()); + } + + { + std::tuple t1(1); + std::tuple t = std::tuple_cat(t1); + assert(std::get<0>(t) == 1); + } + { + std::tuple t = + std::tuple_cat(std::tuple(1, 2)); + assert(std::get<0>(t) == 1); + assert(std::get<1>(t) == 2); + } + { + std::tuple t = std::tuple_cat(std::array()); + assert(std::get<0>(t) == 0); + assert(std::get<1>(t) == 0); + assert(std::get<2>(t) == 0); + } + { + std::tuple t = std::tuple_cat(std::pair(2, 1)); + assert(std::get<0>(t) == 2); + assert(std::get<1>(t) == 1); + } + { std::tuple<> t1; std::tuple<> t2; @@ -112,4 +137,54 @@ int main() assert(std::get<2>(t3) == nullptr); assert(std::get<3>(t3) == 4); } + + { + std::tuple t1(1, 2); + std::tuple t2(nullptr, 4); + std::tuple t3 = + std::tuple_cat(std::tuple<>(), + std::move(t1), + std::move(t2)); + assert(std::get<0>(t3) == 1); + assert(std::get<1>(t3) == 2); + assert(std::get<2>(t3) == nullptr); + assert(std::get<3>(t3) == 4); + } + { + std::tuple t1(1, 2); + std::tuple t2(nullptr, 4); + std::tuple t3 = + std::tuple_cat(std::move(t1), + std::tuple<>(), + std::move(t2)); + assert(std::get<0>(t3) == 1); + assert(std::get<1>(t3) == 2); + assert(std::get<2>(t3) == nullptr); + assert(std::get<3>(t3) == 4); + } + { + std::tuple t1(1, 2); + std::tuple t2(nullptr, 4); + std::tuple t3 = + std::tuple_cat(std::move(t1), + std::move(t2), + std::tuple<>()); + assert(std::get<0>(t3) == 1); + assert(std::get<1>(t3) == 2); + assert(std::get<2>(t3) == nullptr); + assert(std::get<3>(t3) == 4); + } + { + std::tuple t1(1, 2); + std::tuple t2(nullptr, 4); + std::tuple t3 = + std::tuple_cat(std::move(t1), + std::move(t2), + std::tuple(5)); + assert(std::get<0>(t3) == 1); + assert(std::get<1>(t3) == 2); + assert(std::get<2>(t3) == nullptr); + assert(std::get<3>(t3) == 4); + assert(std::get<4>(t3) == 5); + } }