MattG
MattG

Reputation: 263

Adding a base class in c++ template specialization

In the dusty corners of a code base I work on, I've come across a class hierarchy that looks like this:

class Base1
{
  int base1;
};

class Base2
{
  int base2;
};
template <typename T> class A : public Base1
{
      T _specialT;
};
template <> class A<int> : public Base2
{
      int _special;
};

The use of Base2 in the specialization of A is something that surprised me. I've been searching around to understand exactly what it means, haven't been able to find any examples or discussions of this sort of design.

It seems to me that what this does is cause A to inherit from both Base1 and Base2 while other uses of A that are not specialized will inherit from only Base1. That leaves me with a couple of questions:

  1. Do I understand this correctly?
  2. Are there any non-obvious caveats in added to the hierarchy this way? Why would you do this?
  3. Are there times when this would be considered good design?

Upvotes: 4

Views: 782

Answers (3)

Arne Mertz
Arne Mertz

Reputation: 24576

Keep in mind that different instantiations of class templates are different, independent classes. Specializations of templates do not add things to the general case, they replace it completely.

Thus, A<int> is a class that derives from Base2 and has one int member named _special, A<double> and A<char> are two independent, different classes that both happen to derive from Base1 and each have one member of type double and char, respectively, named _specialT.

So:

  1. It seems from your question that you did not understand it correctly.
  2. There are caveats, especially if specializations are defined not directly after the basic template but in another part. It will come as a suprise if a maintainer sees the general definition of A and tries to use some methods of Base1 on an A<int> (or use the _specialT member), getting compiler errors because he did not see the specialization. A very popular example is the specialization of std::vector<bool> in the standard wich behaves differently from the "normal" std::vector and is widely considered broken.
  3. There can be times where some people consider this good design, sometimes a design like this is even considered good by many people. However, design sometimes is a matter of taste, and when it comes to templates and their not-so-typical use cases, many people consider unexpected things like different base classes in specializations as bad style or at least "black template magic", e.g. when it's used in template meta programming.

This pattern (specializations deriving from different bases) is often used in Template Metaprogramming. A (very) simple example:

template <class T>
struct is_int_or_double : std::false_type
{};

template <>
struct is_int_or_double<int> : std::true_type //another base class!
{};

template <>
struct is_int_or_double<double> : std::true_type //another base class!
{};

Upvotes: 2

jrok
jrok

Reputation: 55395

  1. No. The primary class template inherits from Base1 and only the <int> specialization inherits from Base2 (and from Base2 only).

Not knowing the context where this is used, I can't answer 2. or 3.

You can often see specializations deriving from different types in template meta-programming. For example:

template<typename T, typename U>
struct is_same : std::false_type {};

template<typename T>
struct is_same<T,T> : std::true_type {};

It's perfectly valid thing to do. Whether it is a good thing to do depends entirely on the problem being solved.

Upvotes: 4

Sebastian Redl
Sebastian Redl

Reputation: 71909

A specialization of a template is completely independent, code-wise, from the normal case. So A<int> will not derive from both Base1 and Base2, just from Base2.

There are certainly cases where specializations are good design. Whether this is one is not possible to tell from your abstracted example, of course.

Upvotes: 2

Related Questions