Hot.PxL
Hot.PxL

Reputation: 1970

Pass inner template class as template argument in C++

I am trying to pass an inner template class (of a regular class) to another class that accepts templates as arguments.

The class that accepts templates is:

template <typename... T> struct TypeList {
  template <template <typename...> typename P> using Apply = P<T...>;
};

So when I have something like using List = TypeList<int, float, double>; I can do

static_assert(std::is_same<List::template Apply<std::tuple>,
                           std::tuple<int, float, double>>::value);

But if I change std::tuple so an inner template class, it stops working. I.e.,

struct Outer {
  template <typename... P> struct Inner {};
};

static_assert(std::is_same<List::template Apply<typename Outer::Inner>,
                           Outer::Inner<int, float, double>>::value);

doesn't work.

My compiler complains about

error: invalid use of template-name ‘Outer::Inner’ without an argument list

It works if I "flatten" the inner template class with template <typename... P> using Flat = Outer::Inner<P...>;.

My question is, is there a way to make the inner template class work, without aliasing it and flattening it? Am I missing the typename or template keyword somewhere?

Complete example is:

#include <tuple>
#include <type_traits>

template <typename... T> struct TypeList {
  template <template <typename...> typename P> using Apply = P<T...>;
};

struct Outer {
  template <typename... P> struct Inner {};
};

template <typename... P> using Flat = Outer::Inner<P...>;

int main() {
  using List = TypeList<int, float, double>;
  static_assert(std::is_same<List::template Apply<std::tuple>,
                             std::tuple<int, float, double>>::value);
  static_assert(std::is_same<List::template Apply<Flat>,
                             Outer::Inner<int, float, double>>::value);
  static_assert(std::is_same<List::template Apply<typename Outer::Inner>,
                             Outer::Inner<int, float, double>>::value);
}

Upvotes: 1

Views: 192

Answers (1)

Jarod42
Jarod42

Reputation: 217135

typename Outer::Inner is wrong as Inner is not a type but a template.

You can even remove all typename/template here as there is no dependent type issue.

static_assert(std::is_same<List::Apply<Outer::Inner>,
                           Outer::Inner<int, float, double>>::value);

In dependent context, it would be

// template <typename OuterT> /*..*/
static_assert(std::is_same<List::Apply<OuterT::template Inner>,
                           typename OuterT::template Inner<int, float, double>>::value);

Demo

Upvotes: 2

Related Questions