Yury
Yury

Reputation: 1259

Not fully specified template as template argument in C++

In curiously recurring template pattern I need to change nested type T of TDerivedClass<T> type. Is there a way to specify Base by not fully specified Derived1 class? Something like that: class Derived1 : public Base<T, Derived1<"NOT SPECIFIED TYPE SYNTAX">>, and then fully specify Derived1 but inside Base functions as TDerivedClass<int>. Or is there any other way to change T for this specific part of code?

template<typename T, typename TDerivedClass>
class Base
{
public:
    void f()
    {
        std::vector<T> a;
        TDerivedClass b;
        TDerivedClass<int> c; // <- want to change T to arbitrary type (to int for example) without changing T
    }
};

template<typename T>
class Derived1 : public Base<T, Derived1<T>>
{

};

template<typename T>
class Derived2 : public Base<T, Derived2<T>>
{

};

Upvotes: 0

Views: 119

Answers (2)

Artyer
Artyer

Reputation: 40836

You can pass the template class specifically:

template<typename T, template<typename> class TDerivedTemplate>
class Base
{
    using TDerivedClass = TDerivedTemplate<T>;
public:
    void f()
    {
        std::vector<T> a;
        TDerivedClass b;
        TDerivedTemplate<int> c;
    }
};

template<typename T>
class Derived1 : public Base<T, Derived1>  // Pass the template (Derived1) to instantiate new classes from
{

};

// Since you're changing the pattern anyways, you might as well
// have it detect the template from the type

template<typename TDerivedClass>
class Base;

template<template<typename> class TDerivedTemplate, typename T>
class Base<TDerivedTemplate<T>> {
    using TDerivedClass = TDerivedTemplate<T>;
public:
    void f() { /* Same as above */ }
}

template<typename T>
class Derived1 : public Base<Derived1<T>>
// Automatically gets the template. Also means it's harder to use Base<> wrong.
{

};

Or you can use a rebind type trait:

template<typename ToRebind, typename... NewTypes>
struct rebind;

template<template<typename...> class Template, typename... CurrentTypes, typename... NewTypes>
struct rebind<Template<CurrentTypes...>, NewTypes...> {
    using type = Template<NewTypes...>;
}

// Used like
    TDerivedClass b;
    typename rebind<TDerivedClass, int>::type c;

Upvotes: 2

Jarod42
Jarod42

Reputation: 217583

You probably want template template parameter:

template <typename T, template <typename> class TDerivedClass>
class Base
{
public:
    void f()
    {
        std::vector<T> a;
        TDerivedClass<T> b;
        TDerivedClass<int> c;
    }
};

template<typename T>
class Derived1 : public Base<T, Derived1>
{

};

template<typename T>
class Derived2 : public Base<T, Derived2>
{

};

Upvotes: 3

Related Questions