c++templatesc++17autovariadic

Can template parameters match both types and templates seamlessly, perhaps as part of a variadic?


My code is storing some state using a static-type construct similar to the one in Boost.PolyCollection.

My problem is, I think, minimally illustrated by the code below. Basically I'm working with parameter packs and need a way to "instantiate" a given template by what's in the pack.

#include <unordered_map>

template<typename... Ts>
struct Pack
{
    /*
    instantiate a given template with passed types + the types in this Pack
        but passed Template may take non-type template parameters, what to do??
    */
    // template<template<typename...> class Template, typename... As> // error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Ts> template<template<template<class ...> class Template, class ... As> template<class ... Ts> template<class ...> class Template, class ... As> using Inst = Template<As ..., Ts ...>'
    // using Inst = Template<As..., Ts...>;


    // this works for my case, but it's too specific and ugly -
        // am fixing the first of As to be a non-type 
    template<template<template<typename...> class, typename...> class Template, template<typename...> class A1, typename... As>
    using Inst = Template<A1, As..., Ts...>;
};

template<template<typename...> class Segment, typename Key, typename... Ts>
class AnyMap
{
};

int main()
{
    typedef Pack<int, char> ServicePack;
    typedef long Key;

    using ServiceMap = typename ServicePack::template Inst<AnyMap, std::unordered_map, Key>; // AnyMap with given segment type and key
}

I was hoping auto..., which I haven't used much, to come to the rescue, but it seems auto won't match template template params, it's only meant for a Value of inferred type.

Do you know of a simple way to achieve this?

(perhaps evidently, this is about c++17)


Solution

  • There are two related approaches.

    First is boost hana style. Turn everything into compile time values. Templates? A value. Types? A value. Values? An instance of a type like integral constant.

    Metaprogramming is now constexpr programming.

    A second approach is to turn everything into types.

    This includes non-type template parameters of templates.

    template<class T, class N>
    using array=std::array<T,N{}()>;
    
    template<auto x>
    using k=std::integral_constant<decltype(x), x>;
    

    now we can pass k<77> as a type representing the non-type template parameter 77 to array<int,k<77>> and get std::array<int,77>.

    The type-only array template is now easy to metaprogram with. Just write those wrappers once, and metaprogram away.

    Passing templates around can then be:

    template<template<class...>class> struct Z{};
    

    now we can pass Z<array> as a type.