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 provided type_list.

  • type_list_concat, concatenates 2 type_lists, adding second to the end of the first.

  • type_list_expand, expansion of the type_list into std::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 the type_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.

  • Can you explain (1) How your type_list differs from that of Brigand's (GitHub repository)? (2) Why it is necessary/useful to use your type list rather than that one? – einpoklum Mar 2 '17 at 8:33
  • @einpoklum, this is my very old version of type list. They don't even have index based unpacking, so if you're fine with Brigand, please use it. I'll probably update the code once I'll have time, but right now it is not on the top of my todo-list. – Incomputable Mar 2 '17 at 9:08

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.