2

I currently have this class which uses typelist:

template<class AbstractF, template<class, class > class Creator, class TList>
class A: public B<typename Reverse<TList>::Result, Creator, AbstractF> {
};

I'm trying to make the code more c++11 friendly replacing the typelist with variadic template arguments.

template<class AbstractF, template<class, class > class Creator, class TList...>
class A: public B<Creator, AbstractF, TList...> { //<---how to reverse here?
};

The problem is: how to reverse a variadic list? Looking at other questions I saw the use of std::tuple, but in this case I'm not able to understand how to "unpack" it since the variadic arguments are not part of simple templated function but they are used as arguments in a class hierarchy.

Evg
  • 25,259
  • 5
  • 41
  • 83
greywolf82
  • 21,813
  • 18
  • 54
  • 108
  • 1
    Does this answer your question? [How to reverse the order of arguments of a variadic template function?](https://stackoverflow.com/questions/15904288/how-to-reverse-the-order-of-arguments-of-a-variadic-template-function) – Dan M. Dec 26 '19 at 14:17
  • @DanM.No actually, as I said everything is applicable to a function, but in this case there's no function involved, just a list of types used in a class hierarchy. – greywolf82 Dec 26 '19 at 14:22
  • If all the types are distinct, there is a simple solution. If they are not, you can't do it without indirection. – Evg Dec 26 '19 at 14:35
  • 1
    @Evg They should be distinct – greywolf82 Dec 26 '19 at 14:36

2 Answers2

3

If all the types in the pack are distinct, you can compute the type's index from the type itself. All that remains is to extract the N - 1 - index'th type from the pack:

template<std::size_t index, class... Ts>
using Nth_type = std::tuple_element_t<index, std::tuple<Ts...>>;

template<class S, class... Ts>
inline constexpr std::size_t type_index = 0;

template<class S, class T, class... Ts>
inline constexpr std::size_t type_index<S, T, Ts...> = 
    std::is_same_v<S, T> ? 0 : 1 + type_index<S, Ts...>;

template<class T, class... Ts>
using Reverser = Nth_type<sizeof...(Ts) - 1 - type_index<T, Ts...>, Ts...>;

Simple example:

template<class... Ts>
class B;

template<class... Ts>
using RB = B<Reverser<Ts, Ts...>...>;   // two pack expansions here

static_assert(std::is_same<RB<>, B<>>());
static_assert(std::is_same<RB<int>, B<int>>());
static_assert(std::is_same<RB<int, float, double>, B<double, float, int>>());

If the pack is allowed to contain identical types, this trick won't work.

This code uses some C++14/17 features. Variable templates are not part of C++11, so type_index has to be implemented differently. Here is a possible implementation.

Evg
  • 25,259
  • 5
  • 41
  • 83
1

I'm trying to make the code more c++11 friendly replacing the typelist with variadic template arguments

If you use the old typelist way (the link list of type) then in C++11, you can even use unpacked variadic template arguments, or packed variadic template arguments inside std::tuple or similar.

Unpacked way has limitation about manipulations (transformation, skip head, concatenation), and working first with packing way might be needed.

For reordering, packing way might be:

template <typename TypeList, typename Seq> struct ReverseImpl;

template <typename TypeList, std::size_t ... Is>
struct ReverseImpl<TypeList, std::index_sequence<Is...>>
{
    using type = std::tuple<typename std::tuple_element<sizeof...(Is) - 1 - Is, TypeList>::type...>;
};


template <typename TypeList> struct Reverse
{
    using Result =
        typename ReverseImpl<TypeList,
                             std::make_index_sequence<std::tuple_size<TypeList>::value>>::type;
};

Note: std::index_sequence/std::make_index_sequence are C++14, but can be implemented in C++11.

Possible usage might be:

template <template<class, class > class Creator, class AbstractF, typename TypeList>
struct BUnpack;

template<template<class, class > class Creator, class AbstractF, typename ... Ts>
class BUnpack<Creator, AbstractF, std::tuple<Ts...>>
{
    using type = B<Creator, AbstractF, Ts...>;
};

template<class AbstractF, template<class, class > class Creator, typename ... Ts>
class A: public BUnpack<Creator, AbstractF, typename Reverse<std::tuple<Ts...>>::Result>::type {
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302