mercredi 1 novembre 2017

Extracting types from a pack of specific form

P<First, Rest...>, where First is not a pack, shall be called "nice".

P<Q<R<..<<W<T>>>..>>>, where T is "nice", shall be called "cool". And any type that is "nice" is also "cool".

So, let's suppose that we have the "cool" pack

 P<Q<R<..<<Z<First, Rest...>>>..>>>

How do we get extract the type First and std::tuple<Rest...>?

Here is my implementation for the traits classes is_nice and is_cool:

#include <tuple>
#include <type_traits>

template <typename T> struct is_pack : std::false_type {};

template <template <typename...> class P, typename... Ts>
struct is_pack<P<Ts...>> : std::true_type {};

template <typename T> struct is_nice : std::false_type {};

template <template <typename...> class P, typename First, typename... Rest>
struct is_nice<P<First, Rest...>> : std::conditional_t<is_pack<First>::value, std::false_type, std::true_type> {};

template <typename T> struct is_cool : std::conditional_t<is_nice<T>::value, std::true_type, std::false_type> {};

template <template <typename...> class P, typename T>
struct is_cool<P<T>> : std::conditional_t<is_pack<T>::value,
    std::conditional_t<is_cool<T>::value, std::true_type, std::false_type>,
    std::true_type> {};

// Test
template <typename...> class P;
template <typename...> class Q;
template <typename...> class R;

int main () {
    static_assert(is_nice<P<int, bool, char>>::value == true);
    static_assert(is_cool<P<int, bool, char>>::value == true);
    static_assert(is_cool<P<Q<R<int, bool, char>>>>::value == true);
    static_assert(is_nice<P<int>>::value == true);
    static_assert(is_cool<P<int>>::value == true);
    static_assert(is_cool<P<Q<R<int>>>>::value == true);
}

For those wondering what is my use case for this, I'm trying define foo as follows:

template <typename T, typename...>
struct foo { using type = T; };

template <template <typename...> class P, typename First, typename... Rest, typename T, typename... Ts>
struct foo<P<First, Rest...>, T, Ts...> {
    using type = std::pair<First, T>;
};

template <template <typename...> class P, template <typename...> class Q, typename First, typename... Rest, typename T, typename... Ts>
struct foo<P<Q<First, Rest...>>, T, Ts...> {
    using type = std::pair<First, T>;
};

template <template <typename...> class P, template <typename...> class Q, template <typename...> class R, typename First, typename... Rest, typename T, typename... Ts>
struct foo<P<Q<R<First, Rest...>>>, T, Ts...> {
    using type = std::pair<First, T>;
};
// etc... for any number of nested templates in this manner.

template <template <typename...> class P, typename First, typename... Rest>
struct foo<P<First, Rest...>> {
    using type = std::tuple<Rest...>;
};

template <template <typename...> class P, template <typename...> class Q, typename First, typename... Rest>
struct foo<P<Q<First, Rest...>>> {
    using type = std::tuple<Rest...>;
};

template <template <typename...> class P, template <typename...> class Q, template <typename...> class R, typename First, typename... Rest>
struct foo<P<Q<R<First, Rest...>>>> {
    using type = std::tuple<Rest...>;
};
// etc... for any number of nested templates in this manner.

This is what I have so far to implement the above in general:

template <typename T, typename...>
struct foo { using type = T; };

template <typename T, typename Void, typename First, typename... Rest>
struct check_cool {
    using type = T;
};

template <typename T, typename First, typename... Rest>
struct check_cool<T, std::enable_if_t<is_cool<T>::value>, First, Rest...> {
    using type = std::pair<???, First>;
};

template <typename T, typename First, typename... Rest>
struct foo<T, First, Rest...> : check_cool<T, void, First, Rest...> {};

Aucun commentaire:

Enregistrer un commentaire