Class templates are the same idea as for function templates, but extended to classes. They are used by the compiler to generate more specific specialization when we use them in our code.
Consider the following code:
template <typename T>
class BoxContainer {
public:
BoxContainer(size_t capacity);
bool add(const T& item);
private:
T *items;
size_t size;
size_t capacity;
};
We can see this is a template with T being used to define the type of items stored. When we use this class, the compiler will create a specialization for us. The specialization implement only the methods you used. When using template classes the definition must be in the header file as the compiler only uses the header to generate the specializations.
For implementations, we also need to specify the template parameter:
template <typename T>
bool add(const T item) {
Non-type template parameters generate a different specialization for every value passed in. For this reason, they are a bad idea to use and can be replaced with a normal parameter anyway.
Default parameters on class templates work as expected. We pass a type as the default to the template decorator:
template <typename T = int>
We don’t need to add the defaults on the method implementations, just the class declaration.
We can set up a friend of our template class:
// Forward declare to make method definition possible
template <typename T>
class TemplateClass;
<template typename T>
void some_func(TemplateClass<T> param);
<template typename T>
class TemplateClass {
friend void some_func<T>(TemplateClass<T> param);
};
<template typename T>
void some_func(TemplateClass<T> param) {
}
Notice the <T> after some_func in the friend definition. If we leave it our, we’ll get linker errors because the template specializations will not be generated correctly. We can also implement the friend function in the public section of the class. Note that it is still not a member function.
Static asserts and type traits can be used to provide compile-time validation of the type parameter. When using C++20, we can also use concepts to provide compile time checks. If we have split our class definitions to be outside the class, we have to specify the concept on every method.