Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 952
astrophobia Avatar asked Sep 28 '18 23:09

astrophobia


2 Answers

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>...>
like image 129
Jarod42 Avatar answered Sep 18 '22 21:09

Jarod42


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.

like image 42
David Loftus Avatar answered Sep 17 '22 21:09

David Loftus