#pragma once #include namespace utempl { template struct Wrapper; namespace impl { template struct TupleLeaf { T value; template inline constexpr TupleLeaf(TT&& arg) : value(std::forward(arg)) {}; inline constexpr TupleLeaf(const TupleLeaf&) = default; inline constexpr TupleLeaf(TupleLeaf&&) = default; inline constexpr bool operator==(const TupleLeaf&) const = default; }; template struct TupleHelper; template struct TupleHelper, Ts...> : public TupleLeaf... { template inline constexpr TupleHelper(TTs&&... args) : TupleLeaf{std::forward(args)}... {}; inline constexpr TupleHelper(const TupleHelper&) = default; inline constexpr TupleHelper(TupleHelper&&) = default; inline constexpr bool operator==(const TupleHelper&) const = default; }; } // namespace impl template struct Tuple; template inline constexpr auto Get(Tuple& tuple) -> auto& requires (I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return static_cast&>(tuple).value; }; template inline constexpr auto Get(const Tuple& tuple) -> const auto& requires (I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return static_cast&>(tuple).value; }; template inline constexpr auto Get(Tuple&& tuple) -> auto&& requires (I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return std::move(static_cast&&>(tuple).value); }; template inline constexpr auto Get(T&& arg) -> decltype(get(std::forward(arg))) { return get(std::forward(arg)); }; template struct Tuple : public impl::TupleHelper, Ts...> { template inline constexpr Tuple(TTs&&... args) : impl::TupleHelper, Ts...>(std::forward(args)...) {}; inline constexpr Tuple(const Tuple&) = default; inline constexpr Tuple(Tuple&&) = default; inline constexpr bool operator==(const Tuple&) const = default; template inline constexpr auto operator+(const Tuple& other) const -> Tuple { return [&](std::index_sequence, std::index_sequence) -> Tuple { return {Get(*this)..., Get(other)...}; }(std::make_index_sequence(), std::make_index_sequence()); }; template inline constexpr auto operator[](Wrapper) const -> const auto& { return Get(*this); }; template inline constexpr auto operator[](Wrapper) -> auto& { return Get(*this); }; }; template Tuple(Ts&&...) -> Tuple...>; template consteval auto ListFromTuple(Tuple) -> TypeList { return {}; }; } // namespace utempl