TupleCats
TupleCats

Reputation: 351

Template specialization and inheritance template class from other template class

I have some questions about next code:

template<typename T>
class Base;

template<typename T, typename P>
class Base<T(P)> {

};

template<typename T>
class Derived;

template<typename T, typename P>
class Derived<T(P)> : public Base<T(P)> {

};
  1. Class specialization Derived<T(P)> inherits from class template<typename T> class Base or from class template<typename T, typename P> class Base<T(P)>?

  2. What the name of when I'm binding template parameters T and P of class specialization Derived<T(P)> with template parameter T of class Base.

Upvotes: 2

Views: 1058

Answers (2)

aschepler
aschepler

Reputation: 72473

  1. Class specialization Derived<T(P)> inherits from class template<typename T> class Base or from class template<typename T, typename P> class Base<T(P)>?

Technically, neither. A class or class template never inherits from a template, only from one specific base class type. That is, Derived<int(float&)> inherits Base<int(float&)>, and so on. That base class gets instantiated from whatever is the most specialized declaration associated with Base for those specific types. The importance of this distinction comes up if there are additional partial specializations or explicit specializations.

If I change your example a bit,

template<typename T> // #1
class Base;

template<typename T, typename P> // #2
class Base<T(P)> {
public:
    static const int mem1 = 1;
};

template<typename T>
class Derived;

template<typename T, typename P>
class Derived<T(P)> : public Base<T(P)> {
};

class SomethingElse {};

template<typename P> // #3
class Base<SomethingElse(const P&)> {
public:
    static const long long mem2 = 2;
};

using ThingType = Derived<SomethingElse(const std::string&)>;
const auto A = ThingType::mem1; // Error!
const auto B = ThingType::mem2; // OK

It's not correct to say that partial specialization Derived<T(P)> inherits partial specialization Base<T(P)>, since the example type Derived<SomethingElse(const std::string&)> uses that Derived partial specialization, but doesn't use that Base partial specialization at all. Base<T(P)> just means the template called Base, with whatever specialization definition for Base best matches the template argument T(P). The decision about what the base class Base<T(P)> means is made independently for each specific set of template arguments when each specialization of Derived is instantiated.

  1. What the name of when I'm binding template parameters T and P of class specialization Derived<T(P)> with template parameter T of class Base.

I don't know of any term for this, other than that you are using a dependent compound type. (Dependent = depends on one or more template parameters; Compound = the type T(P) involves the other types T and P.) This also makes Base<T(P)> a dependent base class in the definition of Derived<T(P)>, meaning the compiler will not look there for plain identifiers, and you need to use this->name or Base::name to make such names valid. It's also important that the template parameters are in "deducible contexts" within the specialization's template arguments.

Upvotes: 2

Miles Budnek
Miles Budnek

Reputation: 30704

  1. A class instantiated from the template Derived<T(P)> inherits from the class instantiated from Base<T(P)>. Since the type T(P) matches your Base partial specialization, that template will be used to instantiate the class to inherit from.

  2. It's just called inheritance. There's nothing special going on there. You're just instantiating the template Base with the type T(P) and inheriting from the resulting class.


Base<T(P)> will get instantiated when Derived<T(P)> gets instantiated, so Derived<void(int)> inherits from Base<void(int)>. Both of those instantiations will go through the same set of rules to figure out which template to use to instantiate that class.

You may be getting confused thinking that T(P) is some special template thing. It is not. It's just the type "function that returns T and takes a single argument of type P". Granted, types like that don't come up much outside of templates, but they're perfectly legal other places. i.e.

using FuncType = void(int);

// These two declarations are exactly the same
void doAThing(FuncType* callback);
void doAThing(void(*callback)(int));

Upvotes: 2

Related Questions