Search code examples
c++templatestemplate-templates

Altering template template parameters in C++


I would like to design a class that creates internal types that are variants of types passed as template parameters. Something like the following, non-functional example:

template <typename T>
class BaseClass
{
public:
    typedef T InternalType;
    std::vector<InternalType> storage;
};

template <typename Base>
class Injector
{
public:
    typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
    Base<RefinedType> refinedStorage;
};

typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >

Since Base is a fully-specified type, Base<RefinedType> refinedStorage; will fail to compile. Simply using a template template parameter won't work, as the refined type needs to be based on the nested template's parameter as well as its base type.

How can I implement this pattern of creating types based on both the fully-specified and base types of a template parameter?

EDIT: I would like this to be an arbitrary-depth composite, with multiple injector types performing a cascade of transformations. Thus, passing both the template template parameter and the base parameter becomes pretty unwieldy (particularly when it comes to dealing with the base case of the composite), and an ideal solution would use the more direct syntax.


Solution

  • I was able to achieve this by explicitly 're-declaring' the general template inside itself:

    template <typename T>
    class BaseClass
    {
    public:
        typedef T InternalType;
        std::vector<InternalType> storage;
    
        template<class T2>
        using Recur = BaseClass<T2>;
    };
    
    template <typename Base>
    class Injector
    {
    public:
        typedef std::pair<typename Base::InternalType, typename Base::InternalType> RefinedType;
        typename Base::template Recur<RefinedType> refinedStorage;
    };
    
    typedef Injector<BaseClass<int> > InjectedInt; // Should store vector<pair<int, int> >