|
@@ -7,19 +7,10 @@
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
-namespace std {
|
|
|
-
|
|
|
-template <std::size_t I, typename T>
|
|
|
-struct tuple_element;
|
|
|
-
|
|
|
-template <std::size_t I, typename T>
|
|
|
-using tuple_element_t = typename tuple_element<I, T>::type;
|
|
|
-
|
|
|
-template <typename T>
|
|
|
-struct tuple_size;
|
|
|
+#include <bits/tuple_tools>
|
|
|
+#include <bits/sequence>
|
|
|
|
|
|
-template <typename T>
|
|
|
-inline constexpr std::size_t tuple_size_v = tuple_size<T>::value;
|
|
|
+namespace std {
|
|
|
|
|
|
template <std::size_t I, typename T>
|
|
|
struct tuple_element<I, const T> {
|
|
@@ -62,26 +53,6 @@ template <typename... Types>
|
|
|
struct tuple_size<std::tuple<Types...>>
|
|
|
: std::integral_constant<std::size_t, sizeof...(Types)> {};
|
|
|
|
|
|
-template <std::size_t I, typename... Types>
|
|
|
-constexpr auto get(std::tuple<Types...>& tpl) noexcept
|
|
|
- -> tuple_element_t<I, std::tuple<Types...>>&
|
|
|
-{ return tpl.template _getl<I>(); }
|
|
|
-
|
|
|
-template <std::size_t I, typename... Types>
|
|
|
-constexpr auto get(std::tuple<Types...>&& tpl) noexcept
|
|
|
- -> tuple_element_t<I, std::tuple<Types...>>&&
|
|
|
-{ return tpl.template _getr<I>(); }
|
|
|
-
|
|
|
-template <std::size_t I, typename... Types>
|
|
|
-constexpr auto get(const std::tuple<Types...>& tpl) noexcept
|
|
|
- -> tuple_element_t<I, std::tuple<Types...>> const&
|
|
|
-{ return tpl.template _getl<I>(); }
|
|
|
-
|
|
|
-template <std::size_t I, typename... Types>
|
|
|
-constexpr auto get(const std::tuple<Types...>&& tpl) noexcept
|
|
|
- -> tuple_element_t<I, std::tuple<Types...>> const&&
|
|
|
-{ return tpl.template _getr<I>(); }
|
|
|
-
|
|
|
namespace __helpers {
|
|
|
|
|
|
template <std::size_t I, typename Type, typename... Types>
|
|
@@ -218,6 +189,55 @@ public:
|
|
|
constexpr tuple_impl& operator=(tuple_impl&& other) = default;
|
|
|
};
|
|
|
|
|
|
+template <typename... Types>
|
|
|
+struct tuple_constraints {
|
|
|
+ static constexpr std::size_t Tsize = sizeof...(Types);
|
|
|
+
|
|
|
+ template <std::size_t... I>
|
|
|
+ static constexpr auto idx_seq(std::index_sequence<I...> seq)
|
|
|
+ { return seq; }
|
|
|
+
|
|
|
+ template <typename UTuple, typename Seq, typename... UTypes>
|
|
|
+ struct tuple_copy_move_constructible_impl;
|
|
|
+
|
|
|
+ template <typename UTuple, typename... UTypes, std::size_t... I>
|
|
|
+ struct tuple_copy_move_constructible_impl<UTuple,
|
|
|
+ std::index_sequence<I...>, UTypes...> : std::bool_constant<
|
|
|
+ Tsize == sizeof...(UTypes)
|
|
|
+ && (... && std::is_constructible_v<Types, decltype(
|
|
|
+ std::get<I>(std::declval<UTuple>()))>)
|
|
|
+ && ((Tsize != 1) || (!(... && std::is_convertible_v<UTuple, Types>)
|
|
|
+ && !(... && std::is_constructible_v<Types, UTuple>)
|
|
|
+ && !(... && std::is_same_v<Types, UTypes>)))
|
|
|
+ > {};
|
|
|
+
|
|
|
+ template <typename UTuple, typename... UTypes>
|
|
|
+ struct tuple_copy_move_constructible : tuple_copy_move_constructible_impl<
|
|
|
+ UTuple, decltype(idx_seq(std::index_sequence_for<UTypes...>{})), UTypes...> {};
|
|
|
+
|
|
|
+ template <typename Pair, typename = std::index_sequence<0, 1>>
|
|
|
+ struct tuple_pair_constructible;
|
|
|
+
|
|
|
+ template <typename Pair, std::size_t... I>
|
|
|
+ struct tuple_pair_constructible<Pair, std::index_sequence<I...>>
|
|
|
+ : std::bool_constant<sizeof...(Types) == 2
|
|
|
+ && (... && std::is_constructible_v<Types,
|
|
|
+ decltype(std::get<I>(std::declval<Pair>()))>)
|
|
|
+ > {};
|
|
|
+
|
|
|
+ template <typename... Us>
|
|
|
+ struct tuple_pair_copy_assignable : std::bool_constant<
|
|
|
+ sizeof...(Types) == 2
|
|
|
+ && (... && std::is_assignable_v<Types&, const Us&>)
|
|
|
+ > {};
|
|
|
+
|
|
|
+ template <typename... Us>
|
|
|
+ struct tuple_pair_move_assignable : std::bool_constant<
|
|
|
+ sizeof...(Types) == 2
|
|
|
+ && (... && std::is_assignable_v<Types&, Us>)
|
|
|
+ > {};
|
|
|
+};
|
|
|
+
|
|
|
} // namespace __helpers
|
|
|
|
|
|
template <typename... Types>
|
|
@@ -226,36 +246,69 @@ private:
|
|
|
using base = __helpers::tuple_impl<0, Types...>;
|
|
|
|
|
|
template <typename... UTypes, std::size_t... I>
|
|
|
- constexpr void __copy_assignment(const tuple<UTypes...>& other, std::index_sequence<I...>)
|
|
|
+ constexpr void __copy_assignment(
|
|
|
+ const tuple<UTypes...>& other, std::index_sequence<I...>)
|
|
|
{ ((std::get<I>(*this) = std::get<I>(other)), ...); }
|
|
|
|
|
|
template <typename... UTypes, std::size_t... I>
|
|
|
- constexpr void __move_assignment(tuple<UTypes...>&& other, std::index_sequence<I...>)
|
|
|
- { ((std::get<I>(*this) = std::forward<UTypes>(std::get<I>(other))), ...); }
|
|
|
+ constexpr void __move_assignment(
|
|
|
+ tuple<UTypes...>&& other, std::index_sequence<I...>)
|
|
|
+ {
|
|
|
+ ((std::get<I>(*this) = std::forward<UTypes>(std::get<I>(other))), ...);
|
|
|
+ }
|
|
|
|
|
|
public:
|
|
|
+ template <typename _ = void, std::enable_if_t<
|
|
|
+ (... && std::is_default_constructible_v<Types>)
|
|
|
+ && __helpers::template_true_type<_>::value
|
|
|
+ , bool> = true>
|
|
|
constexpr tuple() : base() {}
|
|
|
|
|
|
+ template <typename _ = void, std::enable_if_t<
|
|
|
+ sizeof...(Types) >= 1
|
|
|
+ && (... && std::is_copy_constructible_v<Types>)
|
|
|
+ && __helpers::template_true_type<_>::value
|
|
|
+ , bool> = true>
|
|
|
constexpr tuple(const Types&... args)
|
|
|
: base(args...) {}
|
|
|
|
|
|
- template <typename... UTypes, enable_if_t<
|
|
|
+ template <typename... UTypes, std::enable_if_t<
|
|
|
sizeof...(UTypes) == sizeof...(Types)
|
|
|
&& sizeof...(Types) >= 1
|
|
|
- && !(sizeof...(Types) == 1 && (... && std::is_same_v<tuple, UTypes>))
|
|
|
+ && (... && std::is_constructible_v<Types, UTypes>)
|
|
|
+ && !(sizeof...(Types) == 1
|
|
|
+ && (... && std::is_same_v<tuple, std::remove_cvref_t<UTypes>>))
|
|
|
, bool> = true>
|
|
|
constexpr tuple(UTypes&&... args)
|
|
|
: base(std::forward<UTypes>(args)...) {}
|
|
|
|
|
|
- template <typename... UTypes>
|
|
|
+ template <typename... UTypes, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_copy_move_constructible<const tuple<UTypes...>&, UTypes...>::value
|
|
|
+ , bool> = true>
|
|
|
constexpr tuple(const tuple<UTypes...>& other)
|
|
|
: base(other) {}
|
|
|
|
|
|
- template <typename... UTypes>
|
|
|
+ template <typename... UTypes, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_copy_move_constructible<tuple<UTypes...>&&, UTypes...>::value
|
|
|
+ , bool> = true>
|
|
|
constexpr tuple(tuple<UTypes...>&& other)
|
|
|
: base(std::move(other)) {}
|
|
|
|
|
|
- // TODO: std::pair constructors
|
|
|
+ template <typename U1, typename U2, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_pair_constructible<const std::pair<U1, U2>&>::value
|
|
|
+ , bool> = true>
|
|
|
+ constexpr tuple(const std::pair<U1, U2>& p)
|
|
|
+ : base(std::get<0>(p), std::get<1>(p)) {}
|
|
|
+
|
|
|
+ template <typename U1, typename U2, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_pair_constructible<std::pair<U1, U2>&&>::value
|
|
|
+ , bool> = true>
|
|
|
+ constexpr tuple(std::pair<U1, U2>&& p)
|
|
|
+ : base(std::get<0>(std::move(p)), std::get<1>(std::move(p))) {}
|
|
|
|
|
|
constexpr tuple(const tuple&) = default;
|
|
|
constexpr tuple(tuple&&) = default;
|
|
@@ -263,7 +316,7 @@ public:
|
|
|
constexpr tuple& operator=(const tuple& other) = default;
|
|
|
constexpr tuple& operator=(tuple&& other) = default;
|
|
|
|
|
|
- template <typename... UTypes, enable_if_t<
|
|
|
+ template <typename... UTypes, std::enable_if_t<
|
|
|
sizeof...(Types) == sizeof...(UTypes)
|
|
|
&& (... && std::is_assignable_v<Types&, const UTypes&>)
|
|
|
, bool> = true>
|
|
@@ -273,7 +326,7 @@ public:
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
- template <typename... UTypes, enable_if_t<
|
|
|
+ template <typename... UTypes, std::enable_if_t<
|
|
|
sizeof...(Types) == sizeof...(UTypes)
|
|
|
&& (... && std::is_assignable_v<Types&, UTypes>)
|
|
|
, bool> = true>
|
|
@@ -283,6 +336,28 @@ public:
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
+ template <typename U1, typename U2, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_pair_copy_assignable<U1, U2>::value
|
|
|
+ , bool> = true>
|
|
|
+ constexpr tuple& operator=(const std::pair<U1, U2>& p)
|
|
|
+ {
|
|
|
+ std::get<0>(*this) = p.first;
|
|
|
+ std::get<1>(*this) = p.second;
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename U1, typename U2, std::enable_if_t<
|
|
|
+ __helpers::tuple_constraints<Types...>::template
|
|
|
+ tuple_pair_move_assignable<U1, U2>::value
|
|
|
+ , bool> = true>
|
|
|
+ constexpr tuple& operator=(std::pair<U1, U2>&& p)
|
|
|
+ {
|
|
|
+ std::get<0>(*this) = std::forward<U1>(p.first);
|
|
|
+ std::get<1>(*this) = std::forward<U2>(p.second);
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
constexpr void swap(tuple& other) { std::swap(*this, other); }
|
|
|
};
|
|
|
|
|
@@ -296,19 +371,6 @@ struct ignore_t {
|
|
|
constexpr void operator=(T&&) const noexcept {}
|
|
|
};
|
|
|
|
|
|
-template <typename _T, typename T = std::decay_t<_T>>
|
|
|
-struct __to_tuple_type { using type = T; };
|
|
|
-
|
|
|
-template <typename _T, typename T>
|
|
|
-struct __to_tuple_type<_T, std::reference_wrapper<T>>
|
|
|
-{ using type = std::add_lvalue_reference_t<T>; };
|
|
|
-
|
|
|
-template <typename T, typename Tuple, std::size_t... I>
|
|
|
-constexpr T make_from_tuple_impl(Tuple&& tpl, std::index_sequence<I...>)
|
|
|
-{
|
|
|
- return T { std::get<I>(std::forward<Tuple>(tpl))... };
|
|
|
-}
|
|
|
-
|
|
|
template <typename Func, typename Tuple, std::size_t... I>
|
|
|
constexpr auto apply_impl(Func&& func, Tuple&& tpl, std::index_sequence<I...>)
|
|
|
{
|
|
@@ -330,9 +392,9 @@ constexpr void swap(std::tuple<Types...>& lhs, std::tuple<Types...>& rhs)
|
|
|
|
|
|
template <typename... Types>
|
|
|
constexpr auto make_tuple(Types&&... args)
|
|
|
- -> std::tuple<typename __helpers::__to_tuple_type<Types>::type...>
|
|
|
+ -> std::tuple<__helpers::to_tuple_type_t<Types>...>
|
|
|
{
|
|
|
- return std::tuple<typename __helpers::__to_tuple_type<Types>::type...>
|
|
|
+ return std::tuple<__helpers::to_tuple_type_t<Types>...>
|
|
|
{ std::forward<Types>(args)... };
|
|
|
}
|
|
|
|
|
@@ -348,16 +410,6 @@ constexpr std::tuple<Types&&...> forward_as_tuple(Types&&... args) noexcept
|
|
|
return { std::forward<Types>(args)... };
|
|
|
}
|
|
|
|
|
|
-template <typename T, typename Tuple>
|
|
|
-constexpr T make_from_tuple(Tuple&& tpl)
|
|
|
-{
|
|
|
- return __helpers::make_from_tuple_impl<T>(
|
|
|
- std::forward<Tuple>(tpl),
|
|
|
- std::make_index_sequence<
|
|
|
- std::tuple_size_v<std::remove_cvref_t<Tuple>>> {}
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
template <typename Func, typename Tuple>
|
|
|
constexpr decltype(auto) apply(Func&& func, Tuple&& tpl)
|
|
|
{
|