Last active
July 24, 2019 15:55
-
-
Save gatchamix/39c8af5187e5f54ea6747416c1fa95c4 to your computer and use it in GitHub Desktop.
simple tuple container using C++2a
This file contains 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 <utility> | |
#include <type_traits> | |
// | |
namespace detail | |
{ | |
template <auto I, class T> | |
struct indexer_elem | |
{}; | |
template <class, class...> | |
struct indexer_impl; | |
template <auto... Is, class... Ts> | |
struct indexer_impl<std::index_sequence<Is...>, Ts...> | |
: indexer_elem<Is, Ts>... | |
{}; | |
template <class... Ts> | |
struct indexer | |
: detail::indexer_impl<std::index_sequence_for<Ts...>, Ts...> | |
{}; | |
template <auto I, class T> | |
auto select(indexer_elem<I, T>) | |
-> T; | |
} | |
template <auto I, class... Ts> | |
using type_at = decltype(detail::select<I>(detail::indexer<Ts...>{})); | |
// | |
template <auto...> | |
struct auto_pack | |
{}; | |
template <class...> | |
struct type_pack | |
{}; | |
template <class... Ls, class... Rs> | |
constexpr auto operator+(type_pack<Ls...>, type_pack<Rs...>) | |
{ return type_pack<Ls..., Rs...>{}; } | |
// | |
namespace detail | |
{ | |
template <auto N, class T> | |
struct tuple_elem | |
{ T val_; }; | |
template <class, class...> | |
struct tuple_impl; | |
template <auto... Is, class... Ts> | |
struct tuple_impl<std::index_sequence<Is...>, Ts...> | |
: tuple_elem<Is, Ts>... | |
{ | |
constexpr tuple_impl() = default; | |
template <class... Args> | |
constexpr tuple_impl(Args&&... args) | |
: tuple_elem<Is, Ts> | |
{ | |
static_cast | |
< | |
std::conditional_t | |
< | |
std::is_move_constructible_v<Ts>, | |
Args&&, | |
Args const& | |
> | |
>(args) | |
}... | |
{} | |
}; | |
template <auto I, class T> | |
constexpr auto tuple_element_impl(tuple_elem<I, T>) | |
-> T; | |
} | |
template <class... Ts> | |
struct tuple | |
: detail::tuple_impl<std::index_sequence_for<Ts...>, Ts...> | |
{ | |
constexpr tuple() = default; | |
template <class... Args> | |
requires (sizeof...(Ts) == sizeof...(Args)) | |
constexpr tuple(Args&&... args) | |
: detail::tuple_impl<std::index_sequence_for<Ts...>, Ts...> | |
{ static_cast<Args&&>(args)... } | |
{} | |
}; | |
template <class... Args> | |
tuple(Args&&...) -> tuple<std::decay_t<Args>...>; | |
template <std::size_t I, class T> | |
constexpr auto const& get(detail::tuple_elem<I, T> const& in) noexcept | |
{ return in.val_; } | |
template <std::size_t I, class T> | |
constexpr auto& get(detail::tuple_elem<I, T>& in) noexcept | |
{ return in.val_; } | |
template <std::size_t I, class T> | |
constexpr auto&& get(detail::tuple_elem<I, T>&& in) noexcept | |
{ return std::move(in.val_); } | |
// | |
namespace std | |
{ | |
template <class> | |
struct tuple_size; | |
template <class... Ts> | |
struct tuple_size<::tuple<Ts...>> | |
: integral_constant<size_t, sizeof...(Ts)> | |
{}; | |
template <size_t, class> | |
struct tuple_element; | |
template <size_t I, class... Ts> | |
struct tuple_element<I, ::tuple<Ts...>> | |
{ using type = type_at<I, Ts...>; }; | |
} | |
// | |
template <class... Tups> | |
constexpr auto tuple_cat(Tups&&... ts) | |
{ | |
if constexpr (sizeof...(Tups) < 2) | |
{ | |
return (ts, ...); | |
} | |
else | |
{ | |
constexpr auto indices = [] | |
<auto... Is> | |
(std::index_sequence<Is...>) | |
{ | |
return (... + [] | |
<auto I, auto... J> | |
(std::index_sequence<J...>) | |
{ return type_pack<auto_pack<I, J>...>{}; } | |
.template operator()<Is> | |
(std::make_index_sequence<std::tuple_size<std::decay_t<decltype(ts)>>::value>{})); | |
} | |
(std::index_sequence_for<Tups...>{}); | |
return [&] | |
<auto... I, auto... J> | |
(type_pack<auto_pack<I, J>...>) | |
{ | |
auto big_tup = tuple<Tups&&...>{ static_cast<Tups&&>(ts)... }; | |
return tuple{ std::move(get<J>(get<I>(big_tup)))... }; | |
} | |
(indices); | |
} | |
} | |
// | |
auto main(int argc, char **argv) | |
-> int | |
{ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment