Tasam Farkie
Tasam Farkie

Reputation: 329

Obtain types of variadic types in template template classes

Suppose we have a class

template <int ... values>
struct foo;

now I have a function

template<typename foo_type, typename U>
void bar(foo_type a, U b);

where foo_type is basically foo. My issue is that, I do not want the variable a in the bar function. I want to be able to call the function like so

bar<foo<6,5,7,8,0>>(42);

but have all the parameters of foo available to me in bar. I tried changing the function to

template<template<int...> class foo_type, int ... args, typename U>
void bar(U b)

but this simply does not work. How can I do this? How can I change bar to the above way and still access the parameters in foo? Basically I want to do generic computation on those list at runtime

// within the body of bar
constexpr int[sizeof...(args)] = {args...};

where args is parameters of foo.

Upvotes: 0

Views: 67

Answers (2)

Barry
Barry

Reputation: 302718

How opposed are you to having foo be an argument? Personally, I like having everything be an argument. Just wrap it in an empty type:

template <class T> struct tag_type { using type = T; };
template <class T> constexpr tag_type<T> tag{};

So that you can still template on the ints...:

template<int... Is, typename U>
void bar(tag_type<foo<Is...>> a, U b) {
    constexpr int stuff[sizeof...(Is)] = {Is...};
    // ...
}

Instead of calling bar<foo<6,5,7,8,0>>(42); you'd call bar(tag<foo<6,5,7,8,0>>, 42);, which is close enough.


To get exactly what you want, you can forward the former call to the latter:

namespace details {
    template<int... Is, typename U>
    void bar(tag_type<foo<Is...>> a, U b) {
        constexpr int stuff[sizeof...(Is)] = {Is...};
        // ...
    }
}

template <typename foo_type, typename U>
void bar(U b) {
    details::bar(tag<foo_type>, b);
}

And now it's the best of both worlds.

Upvotes: 2

SergeyA
SergeyA

Reputation: 62553

I believe, the question is about extracting template arguments from given foo type? If I am correct, here is the solution.

You will have to partially specialize a helper class, like following:

template <int ... values>
struct foo { };

template<class T>
struct bar_helper {};

template<int... values> struct bar_helper<foo<values...> > {
  template<class T> static void bar(T ) {
      // Use values... here
  }
};



template<class foo_type, class U>
void bar(U b) {
  bar_helper<foo_type>::bar(b);
}


void check() {
 bar<foo<2, 3, 4, 5, 6> >(42);
}

Upvotes: 0

Related Questions