How to create concrete class from a template class

2.4k Views Asked by At

Say I have a template class:

template <typename T> class StringDeque:
public std::deque<T>
{
public:

    ...

private:
    typedef std::deque<T> BaseClass; 
};

Say I want to create concrete class ArrayString where T=std::string. What is the proper way to achieve that:

define

#define ArrayString StringDeque<string>

typedef

typedef StringDeque < string > ArrayString;

inheritance

class ArrayString :
    public StringDeque < string > {};

I'm not sure whether all of the suggestions are valid. Anyway I'm trying to figure out which practice most fits.

3

There are 3 best solutions below

0
On BEST ANSWER

Proper ways:

typedef std::deque<std::string> StringDeque;
using StringDeque = std::deque<string>;

That said, here are some more notes on your question:

You wrote:

template <typename T> class StringDeque: public std::deque<T> // ...

std container classes are not meant as base classes. This means they should not be inherited from (and inheriting from them is UB).

When you want to use std container functionality in another class, the answer should always be encapsulation. That means, the correct way to build on the functionality of std::queue in your classes is:

template<typename T> class StringDequeue {
    std::deque<T> storage;
public:
    // add interface here that uses storage
};

You also proposed this:

#define ArrayString StringDeque<string>

Please never use define to declare a type. It works, but it has it's own pitfalls and is considered bad practice in C++.

0
On

You want to give a name to a particular type (which happens to be an instantiation of a template). The C++ way to give names (aliases) to types is with a typedef:

typedef StringDeque<string> ArrayString;

Or, since C++11, with an alias declaration:

using ArrayString = StringDeque<string>;

Side note: when thinking about this stuff, it generally helps to think in terms of the correct template terminology. You don't have a "template class" (a class with special properties), you have a "class template" (a template for creating classes). The template is not a type; its instantiations are.

0
On

Create type aliases with typedef or (since C++11) using:

typedef StringDeque<std::string> ArrayString;
using ArrayString = StringDeque<std::string>;

The preprocessor is a sledgehammer: occasionally useful but, with no knowledge of language-level constructs, prone to break code in surprising ways. In this case, I think the only problem is that the name won't be constrained to any scope; but that's reason enough to avoid it.

Inheritance creates a new type; while it's usually usable where the base type is, it's not completely interchangable, and doesn't inherit any constructors from the base type. So that's also not what you want for a simple type alias.