The post is follow up to my previous Typelist with extractor. The type_list
and extraction feature code is identical to the accepted answer (from user2296177). The idea is to provide a type list with fundamental features that users could built something specialized upon that.
List of features, by order of appearance in the code:
type_list
itself.type_list_extract
, extracts Nth type (0 indexed) from the providedtype_list
.type_list_concat
, concatenates 2type_list
s, adding second to the end of the first.type_list_expand
, expansion of thetype_list
intostd::tuple
, supporting extraction by supplied indexes.utility
first_index_holder
, which helps to extract first index from the index interval.utility
reverse_index_interval
, which reverses interval N ... M to M ... N, code has undefined behavior if the interval is not contiguous.type_list_reverse
, reversion of thetype_list
.
The code also provides convenient xxx_t
aliases for all operations, except for first_index_holder
and reverse_index_interval
.
My particular concerns are naming in all parts of the code and optimization (in terms of instantiations) and compile-time (not sure how I could measure this though) of type_list_reverse
.
#include <cstddef>
#include <tuple>
#include <utility>
#include <cassert>
template <class ... Types>
class type_list {};
template <std::size_t idx, class... Types>
class extract
{
static_assert(idx < sizeof...(Types), "index out of bounds");
template <std::size_t i, std::size_t n, class... Rest>
struct extract_impl;
template <std::size_t i, std::size_t n, class T, class... Rest>
struct extract_impl<i, n, T, Rest...>
{
using type = typename extract_impl<i + 1, n, Rest...>::type;
};
template <std::size_t n, class T, class... Rest>
struct extract_impl<n, n, T, Rest...>
{
using type = T;
};
public:
using type = typename extract_impl<0, idx, Types...>::type;
};
template <std::size_t idx, class TypeList>
struct type_list_extract;
template <std::size_t idx, template <class...> class TypeList, class... Types>
struct type_list_extract<idx, TypeList<Types...>>
{
using type = typename extract<idx, Types...>::type;
};
template <std::size_t idx, class TypeList>
using type_list_extract_t = typename type_list_extract<idx, TypeList>::type;
template <class FirstTypeList, class SecondTypeList>
struct type_list_concat;
template <template <class ...> class TypeList, class ... FirstTypesPack, class ... SecondTypesPack>
struct type_list_concat<TypeList<FirstTypesPack...>, TypeList<SecondTypesPack...> >
{
using type = TypeList<FirstTypesPack..., SecondTypesPack...>;
};
template <class FirstTypeList, class SecondTypeList>
using type_list_concat_t = typename type_list_concat<FirstTypeList, SecondTypeList>::type;
template <class TypeList, size_t ... indexes>
struct type_list_expand
{
using type = std::tuple<typename type_list_extract<indexes, TypeList>::type...>;
};
template < template <class...> class TypeList, class ... Types>
struct type_list_expand< TypeList<Types...>>
{
using type = std::tuple<Types...>;
};
template <class TypeList, size_t ... indexes>
using type_list_expand_t = typename type_list_expand<TypeList, indexes...>::type;
template <std::size_t ... indexes>
struct first_index_holder;
template <std::size_t head, std::size_t ... remainder>
struct first_index_holder<head, remainder...>
{
static const std::size_t value = head;
};
template <class IndexInterval>
class reverse_index_interval;
template <template <typename T, T ...> class IndexInterval, std::size_t ... indexes>
class reverse_index_interval < IndexInterval<std::size_t, indexes...>>
{
static const std::size_t size = sizeof...(indexes)-1;
static const std::size_t head = first_index_holder<indexes...>::value;
public:
using type = IndexInterval<std::size_t, (size + head - indexes + head)... >;
};
template <class TypeList>
class type_list_reverse;
template <template <class ... > class TypeList, class ... Types>
class type_list_reverse<TypeList<Types...> >
{
template <class integer_sequence, class TList>
struct typelist_reverse_impl;
template <template <typename T, T ...> class Sequence, std::size_t ... indexes, template<class ...> class TList, class ... Ts>
struct typelist_reverse_impl<Sequence<std::size_t, indexes...>, TList<Ts...>>
{
using type = TList<type_list_extract_t<indexes, TList<Ts...>>...>;
};
public:
using type = typename typelist_reverse_impl<typename reverse_index_interval<std::make_index_sequence<sizeof...(Types)> >::type, TypeList<Types...>>::type;
};
template <class TypeList>
using type_list_reverse_t = typename type_list_reverse<TypeList>::type;
Example usage:
#include <utility>
#include <cassert>
#include "typelist.h"
//just to populate with some types
struct String;
struct Condition;
struct Opinion;
int main()
{
using MyList = type_list<int, char, bool>;
using First = type_list_extract_t<0, MyList>;
static_assert(std::is_same<First, int>::value, "!");
using SecondList = type_list<String, Condition, Opinion>;
using Concat = type_list_concat_t<MyList, SecondList>;
static_assert(std::is_same<type_list<int, char, bool, String, Condition, Opinion>, Concat>::value, "!");
using Expansion = type_list_expand_t<MyList>;
static_assert(std::is_same<std::tuple<int, char, bool>, Expansion>::value, "!");
using PartialExpansion = type_list_expand_t<MyList, 0, 2>; //int, bool
static_assert(std::is_same<std::tuple<int, bool>, PartialExpansion>::value, "!");
constexpr std::size_t sz = first_index_holder<2, 3, 4>::value;
static_assert(sz == 2, "!");
using Seq = std::index_sequence<2, 3, 4>;
using ReversedSeq = reverse_index_interval<Seq>::type;
static_assert(std::is_same<ReversedSeq, std::index_sequence<4, 3, 2> >::value, "!");
using Rev = type_list_reverse_t<MyList>;
static_assert(std::is_same<type_list<bool, char, int>, Rev>::value, "!");
}
Note:
The code doesn't compile in VC++14 (it argues that > is missing before alias named type which belongs to reverse_index_interval
), but does compile on Ideone and c++ shell (GCC 4.9.2). I believe my code is standard conformant.