简体   繁体   中英

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. Ie,

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);
}

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

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