c++metaprogrammingvariadic-templatestemplate-method-pattern

Is it possible to use a modified version of a class template parameter pack in a members template?


I am trying to write a class template with a variadic template parameter pack which is separated into two groups of arguments. Those shall be used in member templates.

template <class... Args>
class Foo {
public:
    Foo(const Args&... args) :gr1{/*...*/}, gr2{/*...*/} {} 
private:
    template_one<Group1...> gr1;
    template_two<Group2...> gr2;
};

What I have come up with is:

A type sorter which returns a pair of tuples containing sorted types.

template <typename... Args>
struct type_sorter;

template <>
struct type_sorter<> {
    constexpr static auto sort() {return std::pair<std::tuple<>, std::tuple<>>{}; }
};

template <typename Arg, typename... Args>
struct type_sorter<Arg, Args...> {
    constexpr static auto sort() {
        auto ret = type_sorter<Args...>::sort();

        if constexpr (std::is_function_v<Arg>)
            return std::make_pair(std::tuple_cat(ret.first, std::tuple<Arg*>{}), ret.second);
        else
            return std::make_pair(ret.first, std::tuple_cat(ret.second, std::tuple<Arg>{}));
    }
};

A param sorter which returns a pair of tuples containing both sorted types and parameters.

template <class Arg>
constexpr auto param_sort(Arg&& arg) {
    if constexpr (std::is_function_v<typename std::remove_reference_t<Arg>>)
        return std::make_pair(std::tuple<Arg>(arg), std::tuple<>());
    else
        return std::make_pair(std::tuple<>(), std::tuple<Arg>(arg));
}

template <class Arg, class... Args>
constexpr auto param_sort(Arg&& arg, Args&&... args) {
    auto ret = param_sort(std::forward<Args>(args)...);

    if constexpr (std::is_function_v<typename std::remove_reference_t<Arg>>)
        return std::make_pair(std::tuple_cat(ret.first, std::tuple<Arg>(arg)), ret.second);
    else
        return std::make_pair(ret.first, std::tuple_cat(ret.second, std::tuple<Arg>(arg)));
}

Currently std::is_function is the sorting criterion. The former can be used to sort types without having to provide arguments while the later sorts both the template parameters and the arguments. This is useful when having only access to the template parameter pack. (At class scope.)

Now they both return tuples:

I would like to be able to extract the parameter packs (Group1, Group2) from the tuples generated by type sorter and use it in the declaration of template_one and template_two.

What I tried is:

template_one<decltype(std::get<
  std::make_index_sequence<std::tuple_size_v<
    decltype(type_sorter<Inputs...>::sort().second)
  >>>(type_sorter<Inputs...>::sort().second)...)
> gr1 {};

Doesn't compile.

Is something like that even possible?


Solution

  • If i correctly understand the question you are looking for a way to get foo<A...> given some std::tuple<A...>.

    You can write a trait for that :

    template <template <typename ...> class T,typename A> 
    struct tuple_expander;
    
    template <template <typename ...> class T,typename ...B>
    struct tuple_expander<T,std::tuple<B...>> {
        using type = T<B...>;
    };
    

    Live Demo