Created
October 24, 2015 02:31
-
-
Save LYP951018/364866a69e2ec20a6761 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <type_traits> | |
| #include <utility> | |
| namespace Yupei | |
| { | |
| //http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4387.html | |
| namespace Internal | |
| { | |
| template<bool...B> | |
| struct StaticAnd; | |
| template<bool B, bool... Args> | |
| struct StaticAnd<B,Args...> : std::__bool_constant<B && StaticAnd<Args...>::value> | |
| { | |
| }; | |
| template<> | |
| struct StaticAnd<> : std::true_type | |
| { | |
| }; | |
| } | |
| template<typename T> | |
| struct remove_reference | |
| { | |
| using type = T; | |
| }; | |
| template<typename T> | |
| struct remove_reference<T&> | |
| { | |
| using type = T; | |
| }; | |
| template<typename T> | |
| struct remove_reference<T&&> | |
| { | |
| using type = T; | |
| }; | |
| template<typename T> | |
| using remove_reference_t = typename remove_reference<T>::type; | |
| template<typename T> | |
| inline constexpr T&& forward(remove_reference_t<T>& value) | |
| { | |
| //lvalue | |
| return static_cast<T&&>(value); | |
| } | |
| template<typename T> | |
| inline constexpr T&& forward(remove_reference_t<T>&& value) | |
| { | |
| //rvalue | |
| return static_cast<T&&>(value); | |
| } | |
| template<typename T> | |
| constexpr remove_reference_t<T>&& move(T&& value) | |
| { | |
| return static_cast<remove_reference_t<T>&&>(value); | |
| } | |
| template<bool TestVal, | |
| typename Type = void> | |
| struct enable_if | |
| { | |
| }; | |
| template<typename Type> | |
| struct enable_if <true, Type> | |
| { | |
| using type = Type; | |
| }; | |
| template<bool B, typename Type = void> | |
| using enable_if_t = typename enable_if<B, Type>::type; | |
| template<typename Type, typename... Args> | |
| using is_nothrow_constructible = std::is_nothrow_constructible<Type, Args...>; | |
| /*bool_constant< | |
| __is_nothrow_constructible(Type, Args...)>;*/ | |
| template<typename Type> | |
| using is_nothrow_default_constructible = is_nothrow_constructible< | |
| Type | |
| >; | |
| template<typename Type> | |
| using is_nothrow_copy_constructible = is_nothrow_constructible< | |
| Type, | |
| const Type& | |
| >; | |
| template<typename Type> | |
| using is_nothrow_move_constructible = is_nothrow_constructible< | |
| Type, | |
| Type&& | |
| >; | |
| namespace Internal | |
| { | |
| /*template<typename T, typename U, typename = void> | |
| struct IsAssignableHelper : false_type | |
| { | |
| }; | |
| template<typename T, typename U> | |
| struct IsAssignableHelper<T, U, void_t< | |
| decltype(Yupei::declval<T>() = Yupei::declval<U>())>> : true_type | |
| { | |
| };*/ | |
| struct WrapInt | |
| { | |
| WrapInt(int){} | |
| }; | |
| template<typename T,typename U> | |
| struct IsAssignableHelper | |
| { | |
| template<typename T1,typename U1> | |
| static std::false_type _Foo(WrapInt); | |
| template<typename T1, typename U1> | |
| static auto _Foo(int)-> | |
| decltype( | |
| (void)(std::declval<T1>() = std::declval<U1>()), std::true_type{}); | |
| using type = decltype(_Foo<T,U>(0)); | |
| }; | |
| } | |
| template<typename T, typename U> | |
| struct is_assignable : Internal::IsAssignableHelper<T, U>::type | |
| { | |
| }; | |
| template<typename T, typename U> | |
| using is_nothrow_assignable = std::__bool_constant< | |
| is_assignable<T,U>::value && noexcept(std::declval<T>() = std::declval<U>()) | |
| >; | |
| template<typename Type> | |
| using is_nothrow_copy_assignable = is_nothrow_assignable< | |
| Type&, | |
| const Type& | |
| >; | |
| template<typename Type> | |
| using is_nothrow_move_assignable = is_nothrow_assignable< | |
| Type&, | |
| Type&& | |
| >; | |
| template<typename Type> | |
| using is_nothrow_copy_assignable = is_nothrow_assignable< | |
| Type&, | |
| const Type& | |
| >; | |
| template<typename Type> | |
| using is_nothrow_move_assignable = is_nothrow_assignable< | |
| Type&, | |
| Type&& | |
| >; | |
| template<typename Type, typename... Args> | |
| struct is_constructible : std::is_constructible<Type,Args...>{}; | |
| template<typename Type> | |
| using is_default_constructible = is_constructible<Type>; | |
| template<typename Type> | |
| using is_copy_constructible = is_constructible< | |
| Type, const Type&>; | |
| template<typename Type> | |
| using is_move_constructible = is_constructible< | |
| Type, Type&&>; | |
| template <typename F,typename T> | |
| using is_convertible = std::is_convertible<F,T>; | |
| struct tuple_alloc_t {}; | |
| constexpr tuple_alloc_t tuple_alloc{}; | |
| template<typename T1, | |
| typename T2> | |
| struct pair; | |
| template<typename... Args> | |
| class tuple; | |
| template<std::size_t Index, | |
| typename T, | |
| bool B = std::is_empty<T>::value && std::is_final<T>::value> | |
| class tuple_leaf; | |
| template<std::size_t Index, | |
| typename T, | |
| bool B> | |
| class tuple_leaf //cannot EBO | |
| { | |
| public: | |
| tuple_leaf() noexcept( | |
| is_nothrow_default_constructible<T>::value) | |
| :value_() | |
| { | |
| } | |
| //why we need support allocator ? | |
| template<typename U, | |
| typename = enable_if_t<!std::is_same<std::decay_t<U>,tuple_leaf>::value && | |
| is_constructible<T,U>::value>> | |
| explicit tuple_leaf(U&& u) noexcept( | |
| is_nothrow_constructible<T, U>::value) | |
| :value_(Yupei::forward<U>(u)) | |
| { | |
| } | |
| tuple_leaf (const tuple_leaf&) = default; | |
| tuple_leaf(tuple_leaf&&) = default; | |
| template<typename U> | |
| tuple_leaf& operator=(U&& u) noexcept( | |
| is_nothrow_assignable<T&,U>::value) | |
| { | |
| value_ = Yupei::forward<U>(u); | |
| } | |
| int swap(tuple_leaf& rhs) noexcept | |
| { | |
| using std::swap; | |
| swap(value_, rhs.value_); | |
| return 0; | |
| } | |
| T& get() noexcept | |
| { | |
| return value_; | |
| } | |
| const T& get() const noexcept | |
| { | |
| return value_; | |
| } | |
| private: | |
| T value_; | |
| }; | |
| template<std::size_t Index, | |
| typename T> | |
| class tuple_leaf<Index,T,true> : private T //EBO enabled. | |
| { | |
| public: | |
| using BaseType = T; | |
| tuple_leaf() noexcept( | |
| is_nothrow_default_constructible<T>::value) | |
| { | |
| } | |
| template<typename U, | |
| typename = enable_if_t<!std::is_same<std::decay_t<U>, tuple_leaf>::value && | |
| is_constructible<T, U>::value >> | |
| explicit tuple_leaf(U&& u) noexcept( | |
| is_nothrow_constructible<T, U>::value) | |
| :BaseType(Yupei::forward<U>(u)) | |
| { | |
| } | |
| tuple_leaf(const tuple_leaf&) = default; | |
| tuple_leaf(tuple_leaf&&) = default; | |
| template<typename U> | |
| tuple_leaf& operator=(U&& u) noexcept( | |
| is_nothrow_assignable<T&, U>::value) | |
| { | |
| BaseType::operator = (Yupei::forward<U>(u)); | |
| } | |
| int swap(tuple_leaf& rhs) noexcept | |
| { | |
| using std::swap; | |
| swap(get(), rhs.get()); | |
| return 0; | |
| } | |
| T& get() noexcept | |
| { | |
| return static_cast<T&>(*this); | |
| } | |
| const T& get() const noexcept | |
| { | |
| return static_cast<const T&>(*this); | |
| } | |
| }; | |
| template<typename... Args> | |
| void swallow(Args&&...) noexcept {} | |
| struct ignore_t | |
| { | |
| template<typename U> | |
| const ignore_t& operator =(U&& u) const noexcept | |
| { | |
| return *this; | |
| } | |
| }; | |
| const ignore_t ignore{}; | |
| template<typename... Args> | |
| struct tuple_types {}; | |
| template<std::size_t Index,typename TupleT> | |
| class tuple_element; | |
| template<std::size_t Index, | |
| typename TupleT> | |
| struct tuple_element<Index, const TupleT> | |
| { | |
| using type = typename tuple_element<Index, TupleT>::type; | |
| }; | |
| template<std::size_t Index, | |
| typename TupleT> | |
| struct tuple_element<Index, volatile TupleT> | |
| { | |
| using type = typename tuple_element<Index, TupleT>::type; | |
| }; | |
| template<std::size_t Index, | |
| typename TupleT> | |
| struct tuple_element<Index, const volatile TupleT> | |
| { | |
| using type = typename tuple_element<Index, TupleT>::type; | |
| }; | |
| template<std::size_t Index> | |
| struct tuple_element<Index, tuple_types<>> | |
| { | |
| static_assert(Index == 0, "tuple_element index out of range."); | |
| static_assert(Index != 0, "tuple_element index out of range."); | |
| }; | |
| template<typename T, | |
| typename... Args> | |
| struct tuple_element<0, tuple_types<T, Args...>> | |
| { | |
| using type = T; | |
| }; | |
| template<std::size_t Index, | |
| typename T, | |
| typename... Args> | |
| struct tuple_element<Index, tuple_types<T, Args...>> | |
| { | |
| using type = typename tuple_element<Index - 1, tuple_types<Args...>>::type; | |
| }; | |
| template<typename... Args> | |
| class tuple; | |
| template<std::size_t Index,typename... Args> | |
| struct tuple_element<Index, tuple<Args...>> | |
| { | |
| using type = typename tuple_element<Index, tuple_types<Args...>>::type; | |
| }; | |
| template<std::size_t Index, | |
| typename TupleT> | |
| using tuple_element_t = typename tuple_element<Index, TupleT>::type; | |
| template<std::size_t Index, | |
| typename... Args> | |
| tuple_element_t<Index, tuple<Args...>>& get(tuple<Args...>&) noexcept; | |
| template<std::size_t Index, | |
| typename... Args> | |
| const tuple_element_t<Index, tuple<Args...>>& get(const tuple<Args...>&) noexcept; | |
| template<std::size_t Index, | |
| typename... Args> | |
| tuple_element_t<Index, tuple<Args...>>&& get(tuple<Args...>&&) noexcept; | |
| namespace Internal | |
| { | |
| template<typename ResTupleT, typename SourceTupleT, std::size_t Start, std::size_t End> | |
| struct make_tuple_types_impl; | |
| template<typename... Args,typename SourceTupleT,std::size_t End> | |
| struct make_tuple_types_impl<tuple_types<Args...>, SourceTupleT, End, End> | |
| { | |
| using type = tuple_types<Args...>; | |
| }; | |
| template<typename... Args,typename SourceTupleT,std::size_t Start,std::size_t End> | |
| struct make_tuple_types_impl<tuple_types<Args...>, SourceTupleT, Start, End> | |
| { | |
| using RTupleT = remove_reference_t<SourceTupleT>; | |
| using type = typename make_tuple_types_impl< | |
| tuple_types<Args..., tuple_element_t<Start, SourceTupleT>>, SourceTupleT, Start + 1, End>::type; | |
| }; | |
| template<typename T> | |
| class tuple_size; | |
| template<typename... Args> | |
| class tuple_size<tuple<Args...>> : public std::integral_constant<std::size_t,sizeof...(Args)> {}; | |
| template< typename T> | |
| class tuple_size<const T> : public std::integral_constant<std::size_t, tuple_size<T>::value> {}; | |
| template< typename T > | |
| class tuple_size<volatile T> : public std::integral_constant<std::size_t, tuple_size<T>::value> {}; | |
| template< typename T > | |
| class tuple_size<const volatile T> : public std::integral_constant<std::size_t, tuple_size<T>::value> {}; | |
| template<typename SourceTupleT, std::size_t Start = 0, std::size_t End = tuple_size<SourceTupleT>::value> | |
| struct make_tuple_types | |
| { | |
| static_assert(Start <= End, "Start > End"); | |
| using type = typename make_tuple_types_impl<tuple_types<>, SourceTupleT, Start, End>::type; | |
| }; | |
| template<typename From, typename To> | |
| struct tuple_convertible : std::false_type {}; | |
| template<typename T, | |
| typename... Args, | |
| typename U, | |
| typename... UArgs> | |
| struct tuple_convertible<tuple_types<T, Args...>, tuple_types<U, UArgs...>> | |
| : std::__bool_constant<is_convertible<T, U>::value && tuple_convertible<tuple_types<Args...>, tuple_types<UArgs...>>::value> {}; | |
| template<> | |
| struct tuple_convertible<tuple_types<>, tuple_types<>> : std::true_type {}; | |
| template<typename, typename> | |
| struct tuple_constructible : std::false_type {}; | |
| template<typename T, | |
| typename... Args, | |
| typename U, | |
| typename... UArgs> | |
| struct tuple_constructible<tuple_types<T, Args...>, tuple_types<U, UArgs...>> | |
| : std::__bool_constant<is_constructible<U, T>::value && tuple_constructible<tuple_types<Args...>, tuple_types<UArgs...>>::value> {}; | |
| template<> | |
| struct tuple_constructible<tuple_types<>, tuple_types<>> : std::true_type {}; | |
| template<typename, typename> | |
| struct tuple_assignable : std::false_type {}; | |
| template<typename T, | |
| typename... Args, | |
| typename U, | |
| typename... UArgs> | |
| struct tuple_assignable<tuple_types<T, Args...>, tuple_types<U, UArgs...>> | |
| : std::__bool_constant<is_assignable<U, T>::value && tuple_assignable<tuple_types<Args...>, tuple_types<UArgs...>>::value> {}; | |
| template<> | |
| struct tuple_assignable<tuple_types<>, tuple_types<>> : std::true_type {}; | |
| } | |
| template<typename IndexT,typename... Args> | |
| class tuple_impl; | |
| template<std::size_t... Index, | |
| typename... Args> | |
| class tuple_impl<std::index_sequence<Index...>,Args...> | |
| :public tuple_leaf<Index,Args>... | |
| { | |
| public: | |
| constexpr tuple_impl() noexcept( | |
| Internal::StaticAnd<is_nothrow_default_constructible<Args>::value...>::value ) | |
| {} | |
| template<typename... ParamsT, | |
| typename = enable_if_t<sizeof...(ParamsT) == sizeof...(Args)>> | |
| tuple_impl(ParamsT&&... params) /*noexcept( | |
| Internal::StaticAnd<is_nothrow_constructible<Args, ParamsT>::value...>::value)*/ | |
| :tuple_impl::tuple_impl(std::make_index_sequence<sizeof...(ParamsT)>(),tuple_types<ParamsT...>(),Yupei::forward<ParamsT>(params)...) | |
| { | |
| static_assert(sizeof...(ParamsT) == sizeof...(Args), "hahaha"); | |
| } | |
| template<std::size_t... Index1,typename... TArgs, | |
| typename... ParamsT, | |
| typename = enable_if_t<sizeof...(ParamsT) == sizeof...(Args) && sizeof...(Index1) == sizeof...(ParamsT)>> | |
| tuple_impl(std::index_sequence<Index1...>, tuple_types<TArgs...>, | |
| ParamsT&&... params) noexcept( | |
| Internal::StaticAnd<is_nothrow_constructible<TArgs, ParamsT>::value...>::value) | |
| :tuple_leaf<Index1,TArgs>(Yupei::forward<TArgs>(params))... | |
| { | |
| } | |
| template<typename TupleT, | |
| typename = enable_if_t<Internal::tuple_constructible<TupleT,tuple<Args...>>::value>> | |
| tuple_impl(TupleT&& rhs) noexcept(Internal::StaticAnd<is_nothrow_constructible<Args, | |
| tuple_element_t<Index,TupleT>>::value...>::value | |
| ) | |
| :tuple_leaf<Index,Args>(Yupei::forward<tuple_element_t<Index,TupleT>>(get<Index>(rhs)))... | |
| { | |
| } | |
| template<typename TupleT, | |
| typename = enable_if_t< | |
| Internal::tuple_assignable<TupleT,tuple<Args...>>::value>> | |
| tuple_impl& operator = (TupleT&& t) noexcept( | |
| Internal::StaticAnd<is_nothrow_assignable<Args&,tuple_element_t<Index,TupleT>>::value...>::value) | |
| { | |
| swallow(tuple_leaf<Index, Args>::operator = (Yupei::forward<tuple_element_t<Index, TupleT>>(get<Index>(t)))...); | |
| } | |
| tuple_impl(const tuple_impl&) = default; | |
| tuple_impl(tuple_impl&&) = default; | |
| tuple_impl& operator=(const tuple_impl& t) | |
| noexcept(Internal::StaticAnd<is_nothrow_copy_assignable<Args>::value...>::value) | |
| { | |
| swallow(tuple_leaf<Index, Args>::operator = (static_cast<const tuple_leaf<Index, Args>&>(t).get())...); | |
| return *this; | |
| } | |
| tuple_impl& operator=(tuple_impl&& t) | |
| noexcept(Internal::StaticAnd<is_nothrow_move_assignable<Args>::value...>::value) | |
| { | |
| swallow(tuple_leaf<Index, Args>::operator = (Yupei::forward<Args>(static_cast<tuple_leaf<Index,Args>&>(t).get()))...); | |
| return *this; | |
| } | |
| void swap(tuple_impl& rhs) | |
| { | |
| swallow(tuple_leaf<Index, Args>::swap(static_cast<tuple_leaf<Index, Args>&>(rhs))...); | |
| } | |
| }; | |
| template<typename... Args> | |
| class tuple | |
| { | |
| using BaseType = tuple_impl<std::make_index_sequence<sizeof...(Args)>, Args...>; | |
| BaseType base_; | |
| public: | |
| static constexpr auto tuple_size = sizeof...(Args); | |
| public: | |
| template<std::size_t Index, | |
| typename... UArgs> | |
| friend tuple_element_t<Index, tuple<UArgs...>>& get(tuple<UArgs...>&) noexcept; | |
| template<std::size_t Index, | |
| typename... UArgs> | |
| friend const tuple_element_t<Index, tuple<UArgs...>>& get(const tuple<UArgs...>&) noexcept; | |
| template<std::size_t Index, | |
| typename... UArgs> | |
| friend tuple_element_t<Index, tuple<UArgs...>>&& get(tuple<UArgs...>&&) noexcept; | |
| template<typename = enable_if_t<Internal::StaticAnd<is_default_constructible<Args>::value...>::value>> | |
| constexpr tuple() noexcept( | |
| is_nothrow_default_constructible<BaseType>::value) | |
| {} | |
| template< | |
| typename Dummy = void, | |
| enable_if_t<tuple_size >= 1 && | |
| std::is_same<Dummy,void>::value | |
| && Internal::StaticAnd<is_copy_constructible<Args>::value...>::value && | |
| Internal::StaticAnd<is_convertible<const Args&,Args>::value...>::value,bool> = true> | |
| tuple(const Args&... args) noexcept( | |
| is_nothrow_constructible<BaseType, const Args&...>::value) | |
| :base_(args...) | |
| { | |
| } | |
| template< | |
| typename Dummy = void, | |
| enable_if_t<tuple_size >= 1 && | |
| std::is_same<Dummy, void>::value | |
| && Internal::StaticAnd<is_copy_constructible<Args>::value...>::value && | |
| !Internal::StaticAnd<is_convertible<const Args&, Args>::value...>::value,bool> = false> | |
| explicit tuple(const Args&... args) | |
| noexcept( | |
| is_nothrow_constructible<BaseType, const Args&...>::value) | |
| :base_(args...) | |
| { | |
| } | |
| template<typename... UArgs, | |
| enable_if_t<sizeof...(Args) >= 1 && sizeof...(UArgs) == sizeof...(Args) | |
| && Internal::StaticAnd<is_constructible<Args,UArgs&&>::value...>::value | |
| && Internal::StaticAnd<is_convertible<UArgs&&, Args>::value...>::value,bool> = false> | |
| tuple(UArgs&&... args)/*noexcept( | |
| is_nothrow_constructible<BaseType, UArgs&&...>::value)*/ | |
| :base_(Yupei::forward<UArgs>(args)...) | |
| { | |
| } | |
| template<typename... UArgs, | |
| enable_if_t<tuple_size >= 1 && sizeof...(UArgs) == tuple_size | |
| && Internal::StaticAnd<is_constructible<Args, UArgs&&>::value...>::value && | |
| !Internal::StaticAnd<is_convertible<UArgs&&, Args>::value...>::value,bool> = true> | |
| explicit tuple(UArgs&&... args) | |
| noexcept( | |
| is_nothrow_constructible<BaseType,UArgs&&...>::value) | |
| :base_(Yupei::forward<UArgs>(args)...) | |
| { | |
| } | |
| tuple(const tuple&) = default; | |
| tuple(tuple&&) = default; | |
| template<typename... UArgs, | |
| enable_if_t<Internal::StaticAnd<is_constructible<Args,const UArgs&>::value...>::value&& | |
| sizeof...(UArgs) == tuple_size && | |
| Internal::StaticAnd<is_convertible<const UArgs&,Args>::value...>::value,bool> = false> | |
| constexpr tuple(const tuple<UArgs...>& rhs) | |
| noexcept(is_nothrow_constructible<BaseType,const tuple<UArgs...>&>::value) | |
| :base_(rhs) | |
| { | |
| } | |
| template<typename... UArgs, | |
| enable_if_t<Internal::StaticAnd<is_constructible<Args, const UArgs&>::value...>::value&& | |
| sizeof...(UArgs) == tuple_size && | |
| !Internal::StaticAnd<is_convertible<const UArgs&, Args>::value...>::value,bool> = true> | |
| constexpr explicit tuple(const tuple<UArgs...>& rhs) | |
| noexcept(is_nothrow_constructible<BaseType, const tuple<UArgs...>&>::value) | |
| :base_(rhs) | |
| { | |
| } | |
| template<typename... UArgs, | |
| enable_if_t<Internal::StaticAnd<is_constructible<Args, UArgs&&>::value...>::value&& | |
| sizeof...(UArgs) == tuple_size && | |
| Internal::StaticAnd<is_convertible<UArgs&&, Args>::value...>::value,bool> = false> | |
| constexpr tuple(tuple<UArgs...>&& rhs) | |
| noexcept(is_nothrow_constructible<BaseType, tuple<UArgs...>&&>::value) | |
| :base_(Yupei::move(rhs)) | |
| { | |
| } | |
| template<typename... UArgs, | |
| enable_if_t<Internal::StaticAnd<is_constructible<Args, UArgs&&>::value...>::value&& | |
| sizeof...(UArgs) == tuple_size && | |
| !Internal::StaticAnd<is_convertible<UArgs&&, Args>::value...>::value,bool> = false> | |
| constexpr explicit tuple(tuple<UArgs...>&& rhs) | |
| noexcept(is_nothrow_constructible<BaseType, tuple<UArgs...>&&>::value) | |
| :base_(Yupei::move(rhs)) | |
| { | |
| } | |
| void swap(tuple& rhs) | |
| { | |
| base_.swap(rhs.base_); | |
| } | |
| }; | |
| template<> | |
| class tuple<> | |
| { | |
| constexpr tuple() noexcept = default; | |
| void swap(tuple&) noexcept {} | |
| }; | |
| template<typename... Args> | |
| void swap(tuple<Args...>& lhs, tuple<Args...>& rhs) | |
| { | |
| lhs.swap(rhs); | |
| } | |
| /*template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator == (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return lhs.Equal(rhs); | |
| } | |
| template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator < (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return lhs.Less(rhs); | |
| } | |
| template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator != (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return !lhs.Equal(rhs); | |
| } | |
| template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator > (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return rhs.Less(lhs); | |
| } | |
| template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator <= (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return !rhs.Less(lhs); | |
| } | |
| template<typename... Args, | |
| typename... UArgs> | |
| constexpr bool operator >= (const tuple<Args...>& lhs, const tuple<UArgs...>& rhs) | |
| { | |
| return !lhs.Less(rhs); | |
| }*/ | |
| template< std::size_t I, typename... Args,typename = enable_if_t< (I < sizeof...(Args)) > > | |
| inline constexpr tuple_element_t<I, tuple<Args...> >& get(tuple<Args...>&t) | |
| { | |
| return static_cast<tuple_leaf<I, tuple_element_t<I, tuple<Args...>>>&>(t.base_).get(); | |
| } | |
| template< std::size_t I, typename... Args, typename = enable_if_t<( I < sizeof...(Args))> > | |
| inline constexpr const tuple_element_t<I, tuple<Args...> >& get(const tuple<Args...>& t) | |
| { | |
| return static_cast<const tuple_leaf<I, tuple_element_t<I, tuple<Args...>>>&>(t.base_).get(); | |
| } | |
| template< std::size_t I, typename... Args, typename = enable_if_t< (I < sizeof...(Args)) > > | |
| inline constexpr tuple_element_t<I, tuple<Args...> >&& get(tuple<Args...>&& t) | |
| { | |
| return static_cast<tuple_leaf<I, tuple_element_t<I, tuple<Args...>>>&&>(t.base_).get(); | |
| } | |
| template<typename... Args> | |
| inline constexpr tuple<Args&...> tie(Args&... t) noexcept | |
| { | |
| return tuple<Args&...>(t...); | |
| } | |
| namespace Internal | |
| { | |
| template<typename TypeToFind, | |
| typename Type, | |
| std::size_t NowIndex> | |
| struct get_tuple_by_type_checker; | |
| template<typename TypeToFind, | |
| typename Type, | |
| std::size_t NowIndex> | |
| struct get_tuple_by_type_impl; | |
| template<typename TypeToFind, | |
| typename Type | |
| > | |
| struct get_tuple_by_type; | |
| template<typename TypeToFind, | |
| typename Type, | |
| typename... Args, | |
| std::size_t NowIndex> | |
| struct get_tuple_by_type_impl < TypeToFind, tuple<Type, Args...>,NowIndex> | |
| { | |
| static constexpr std::size_t value = std::conditional_t < | |
| std::is_same<TypeToFind, Type>::value, | |
| get_tuple_by_type_checker<TypeToFind,tuple<Args...>,NowIndex >,//find it,check. | |
| get_tuple_by_type_impl < TypeToFind, tuple<Args...>, NowIndex + 1 > | |
| >::value; | |
| }; | |
| template<typename TypeToFind, | |
| std::size_t NowIndex> | |
| struct get_tuple_by_type_impl < TypeToFind, tuple<>, NowIndex> | |
| { | |
| static constexpr std::size_t value = -1; | |
| }; | |
| template<typename TypeToFind, | |
| typename... Args, | |
| std::size_t NowIndex> | |
| struct get_tuple_by_type_checker<TypeToFind,tuple<Args...>,NowIndex> | |
| { | |
| static_assert(get_tuple_by_type_impl<TypeToFind, tuple<Args...>, 0>::value == -1, "tuple get<>() type duplicate"); | |
| static constexpr std::size_t value = NowIndex; | |
| }; | |
| template<typename TypeToFind, | |
| typename... Args | |
| > | |
| struct get_tuple_by_type<TypeToFind, tuple<Args...>> | |
| { | |
| static constexpr std::size_t value = get_tuple_by_type_impl< | |
| TypeToFind, | |
| tuple<Args...>, | |
| 0>::value; | |
| static_assert(value != -1, "type not found."); | |
| }; | |
| } | |
| template< typename Type, typename... Args> | |
| inline constexpr decltype(auto) get(tuple<Args...>&& t) noexcept | |
| { | |
| return Yupei::get<Internal::get_tuple_by_type<Type, tuple<Args...>>::value >(Yupei::forward<tuple<Args...>&&>(t)); | |
| } | |
| template< typename Type, typename... Args > | |
| inline constexpr decltype(auto) get(tuple<Args...>& t) noexcept | |
| { | |
| return Yupei::get<Internal::get_tuple_by_type<Type, tuple<Args...>>::value >(t); | |
| } | |
| template< typename Type, typename... Args > | |
| inline constexpr decltype(auto) get(const tuple<Args...>& t) noexcept | |
| { | |
| return Yupei::get<Internal::get_tuple_by_type<Type, tuple<Args...>>::value >(t); | |
| } | |
| template<class... Args> | |
| inline constexpr tuple<Args&&...> forward_as_tuple(Args&&... t) noexcept | |
| { | |
| return tuple<Args&&...>(Yupei::forward<Args>(t)...); | |
| } | |
| } | |
| int main() | |
| { | |
| Yupei::tuple<int,int,int,int,int> a(1,3,4,5,6); | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment