Cascade variadic template template parameters

89 Views Asked by At

How can I cascade variadic types? I.e.:

template <typename... T>
using Cascade = ???; // T1<T2<T3<...>>>

Example:

using Vector2D = Cascade<std::vector, std::vector, double>;
static_assert(std::is_same_v<Vector2D, std::vector<std::vector<double>>>);
2

There are 2 best solutions below

6
n. m. could be an AI On BEST ANSWER

You cannot have CascadeRight. T1 is not a typename, it is a template, and so are most of the others, but the last one is a typename. You cannot have different parameter kinds (both types and templates) in the same parameter pack. You also cannot have anything after a parameter pack.

You can have CascadeLeft like this:

  template <typename K, template <typename...> class ... T>
  class CascadeLeft;                  
                                      
  template <typename K>               
  class CascadeLeft<K>                
  {                                   
      using type = K;                 
  };                                  
                                      
  template <typename K, 
            template <typename...> class T0, 
            template <typename...> class... T>
  class CascadeLeft<K, T0, T...>      
  {                                   
      using type = typename CascadeLeft<T0<K>, T...>::type;
  };   

Frankly, std::vector<std::vector<double>> is much more transparent than CascadeLeft<double, std::vector, std::vector>, so I wouldn't bother.

0
Roman On

Expanding on the accepted answer with CascadeRight and support for multiple types for the innermost template:

template<template<typename...> typename Head, template<typename...> typename... Tail>
struct CascadeRight {
    template<typename... T>
    using type = Head<typename CascadeRight<Tail...>::type<T...>>;
};

template<template<typename...> typename Head>
struct CascadeRight<Head> {
    template<typename... T>
    using type = Head<T...>;
};

template<template<typename...> typename Head, template<typename...> typename... Tail>
struct CascadeLeft {
    template<typename... T>
    using type = typename CascadeLeft<Tail...>::type<Head<T...>>;
};

template<template<typename...> typename Head>
struct CascadeLeft<Head> {
    template<typename... T>
    using type = Head<T...>;
};
using T1 = CascadeRight<std::vector, std::map>::type<int, double>;
using T2 = CascadeLeft<std::map, std::vector>::type<int, double>;