samedi 24 février 2018

Recursively folding a parameter pack to resolve placeholder types

Notice: Followup to this question

After asking this question about parameter pack folding into pairs, I noticed that I need to retain the complete type of the previously folded type as the left pair type.

For example:

Fold<char, int, long> f;

must evaluate to

std::tuple<
    std::pair<char, int>,
    std::pair<std::pair<char, int> /* <-- the previous resulting type */
             , long>
> f;

Context to this problem

The reason why I need this, is because the types which have to be "folded" can be placeholder types. The placeholders "real" type can only be known when both having the fully expanded type to the left as well as the unexpanded type. The leftmost type never contains placeholders.

Let me illustrate this with a quick example:

struct CopyTypeFromPreviousArgumentTag { };

template<typename T = CopyTypeFromPreviousArgumentTag>
struct Foo;

template<typename T...>
struct Bar {
    Fold<T...> expanded;
};

Now Bar can be used like this:

Bar< Foo<int>
   , Foo<>
   , Foo<>
   , Foo<double>
   , Foo<>
   > f;

and the internal type decltype(f::expanded) will be:

std::tuple< Foo<int>
          , Foo<int>
          , Foo<int>
          , Foo<double>
          , Foo<double>
          >;

My current attempt

I tried to implement the recursion by building upon the answer from the linked question, but can't get it to work.

namespace Detail {

template<typename, typename...>
struct Fold;

template
    < size_t... Indices
    , typename... Types
> struct Fold<std::index_sequence<Indices...>, Types...> {
    using Tuple = std::tuple<Types...>;
    using Type = std::tuple<std::pair /* use std::pair just to match the first example */
        //< std::tuple_element_t<Indices, Tuple>
        < typename Fold
            < std::tuple_element_t<Indices, Tuple>
            , std::make_index_sequence<Indices>
            , Types...>::Type; /* Tuple can't be expanded :( */
        , std::tuple_element_t<Indices + 1, Tuple>
        >::Type...>;
};

} /* namespace Detail */


template<typename... Types>
using Fold = typename Detail::Fold<std::make_index_sequence<sizeof...(Types) - 1>, Types...>::Type;

Aucun commentaire:

Enregistrer un commentaire