简体   繁体   中英

unpacking variadic template arguments to define new template arguments

I am new to template programming and I have two questions...Hopefully someone can help me. I am trying to use variadic templates to generate a new input to another variadic template. In other words, I have a class

template <std::size_t N, std::size_t... M>
class Class1 {

}

I want to use the integer values represented by N,M to generate a new set of std::bitset type inputs to another templated class

template <typename T, typename... Ts>
class Class2 {

}

So for example if I use Class1<10,20,25> I want inside the body of Class1 to create a Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>> variable. Is there a simple way to do this using C++11?

My second question then is how can I abstract this even more so that the unpacking is not specific to the std::bitset class? Is there a way to modify the Class1 template definition so that I can expand some arbitrary templated class that I develop instead of std::bitset ?

You might write something like:

template <std::size_t N, std::size_t... M>
class Class1 {
    template <template <typename, typename...> class C,
              template <std::size_t> class inner>
    using rebind_with_type = C<inner<N>, inner<M>...>;
};

And then

Class1<10, 20, 25>::rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<10>, std::bit_set<20>, std::bit_set<25>>

And if call it with dependent name, don't forget typename / template :

typename Class1<N, M...>::template rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<N>, std::bit_set<M>...>

I find you can think of the ... operator on parameter packs in this way:

f(g(Xs)...);

will expand to

f(g(Xs1), g(Xs2), ..., g(Xsn));

for any operations f and g. Really all it is doing is adding a comma seperated list of g applied to each of the parameters provided. The ... defines where it should begin the expansion These operations can be for types or values, so in your case our f is Class2<...> and our g is std::bitset our type would look like

Class2<std::bitset<N>, std::bitset<M>...>

The first one needs to be explicitly added since it's not part of the parameter pack ofcourse.

The other answers are excellent but let me give you an even more generic version of the accepted answer. You basically create a using alias that takes two templates, the first is the class that will hold the class templates as template parameters, and the second the template (like bitset ) that you want to pass types to.

template<template<class...> class Y, template<class...> class Z, class... Ts>
using fold_types_into_t = Y<Z<Ts>...>;
template<template<class...> class Y, template<auto...> class Z, auto... Vs>
using fold_values_into_t = Y<Z<Vs>...>;

template<class,class...>
struct Class2;

template <std::size_t N, std::size_t... M>
class Class1 {
  // Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>>
  using T=fold_values_into_t<Class2, std::bitset, N, M...>;
};

There could also be added support for classes that take values as well as types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM