问题
I was wondering if it is possible to capture an alternating parameter pattern using a parameter pack. For example,
template<typename T, size_t U, typename... Args>
class foo<T, U, Args...>
{
public:
foo() : my_T(nullptr), my_U(U) {}
private:
T* my_T;
size_t my_U;
foo<Args...> my_next_foo;
}
So this doesn't work since Args is a parameter pack of only types. Is there a way to modify this so that the typename T, size_t U pattern can be properly captured in a variadic template? Thanks
回答1:
Values as template parameters are second class citizens, in my experience.
Upgrade them to first class with an alias:
template<std::size_t n>
using size = std::integral_constant<std::size_t, n>;
then pattern match:
template<class...>
struct foo;
template<>
struct foo<> {
// empty
};
template<class T, size_t U, typename... Args>
struct foo<T, size<U>, Args...> {
foo() : my_T(nullptr), my_U(U) {}
private:
T* my_T;
size_t my_U;
foo<Args...> my_next_foo;
};
and bob is your uncle.
Note, however, that taking U
as a template parameter, then storing it as a run time value, is highly questionable.
Users of foo
must do:
foo< Chicken, size<3>, Dog, size<17> >
instead of
foo< Chicken, 3, Dog, 17 >
回答2:
Sure, just write your own pair:
template <typename T, size_t U>
struct foo_pair { };
And have a pack of those:
template<typename T, size_t U, typename... Pairs>
class foo<foo_pair<T, U>, Pairs...> {
...
};
Which would be instantiated like:
foo<foo_pair<int, 4>, foo_pair<char, 17>, ...> f;
回答3:
You can pass Args
to foo
as an std::tuple
. Use std::integral_constant
for U
instead of passing an integral constant as a template parameter to the std::tuple
. Then the Args
parameters pack contains all the pairs of types and sizes.
For example, when instantiating foo you would do so with a type like this:
Foo<std::tuple<int, std::integral_constant<size_t, 5> >,
std::tuple<char, std::integral_constant<size_t, 3> > >
When implementing foo
, you should pass your parameter pack to another std::tuple
and use std::tuple_element
to select the Nth element of the tuple.
This is just one possible approach, you may find it easier to implement foo
if you use type lists.
回答4:
You might create a class representing the data container T* my_T
with size_t my_U
. Having that, you can implement your template:
#include <array>
using std::size_t;
template<typename... Args>
struct foo;
template<typename T, size_t N>
struct foo<std::array<T, N>>
{
std::array<T, N> array;
};
template<typename T, size_t N, typename... Args>
struct foo<std::array<T, N>, Args...>
{
std::array<T, N> array;
foo<Args...> next_array;
};
int main() {
foo<std::array<char, 1>, std::array<short, 2>, std::array<int, 4>> foos;
}
Note: I am using std::array as an replacement for the data container.
来源:https://stackoverflow.com/questions/30487378/variadic-template-parameter-packs-with-alternating-types