Skip to content

Instantly share code, notes, and snippets.

@gatchamix
Last active July 24, 2019 15:55
Show Gist options
  • Save gatchamix/39c8af5187e5f54ea6747416c1fa95c4 to your computer and use it in GitHub Desktop.
Save gatchamix/39c8af5187e5f54ea6747416c1fa95c4 to your computer and use it in GitHub Desktop.
simple tuple container using C++2a
#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