Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A class template is a programmer-defined blueprint that allows the definition of a class with parameterized types. It enables the creation of a family of classes by deferring the specification of one or more data types or values until the class is instantiated by the compiler.

Basic Syntax

A class template is declared using the template keyword followed by a template parameter list enclosed in angle brackets < >.
template <typename T>
class ClassName {
private:
    T memberVariable;
public:
    ClassName(T arg);
    T getMember() const;
};
Note: The keywords typename and class are functionally identical within a type template parameter declaration.

Template Instantiation

When a class template is used, the compiler performs instantiation, generating a concrete class definition based on the provided template arguments. Implicit Instantiation Occurs automatically when an object of the template class is declared or when a complete type is required.
struct MyStruct {};
MyStruct myStructInstance;

// Implicitly instantiating the template with 'int'
ClassName<int> intObject(10);

// Implicitly instantiating the template with a custom type
ClassName<MyStruct> structObject(myStructInstance);
Explicit Instantiation Forces the compiler to generate the class definition for a specific type without creating an object. To effectively reduce compilation times across multiple translation units, this requires a two-part approach introduced in C++11:
  1. Explicit Instantiation Declaration (extern template): Placed in a header file, this suppresses the compiler from implicitly instantiating the template in every translation unit that includes the header.
  2. Explicit Instantiation Definition: Placed in exactly one .cpp file, this forces the compiler to generate the actual instantiation.
// In header file: Explicit Instantiation Declaration
extern template class ClassName<int>;

// In exactly one .cpp file: Explicit Instantiation Definition
template class ClassName<int>;

Out-of-Line Member Function Definition

If member functions are defined outside the class body, the template declaration must precede each function definition, and the class name must include the template parameter list.
template <typename T>
ClassName<T>::ClassName(T arg) : memberVariable(arg) {}

template <typename T>
T ClassName<T>::getMember() const {
    return memberVariable;
}

Template Parameter Types

Class templates support three primary categories of parameters: 1. Type Parameters Standard parameters representing arbitrary data types.
template <typename T, typename U>
class Pair {
    T first;
    U second;
};
2. Non-Type Template Parameters (NTTP) Parameters representing constant values evaluated at compile-time. These are restricted to structural types (e.g., integral types, enumerations, pointers, and, as of C++20, literal class types).
#include <cstddef>

template <typename T, std::size_t Size>
class StaticBuffer {
    T buffer[Size]; 
};

// Instantiation
StaticBuffer<double, 256> myBuffer;
3. Template Template Parameters Parameters that are themselves class templates. This allows a template to accept another template as an argument without fully specifying the inner template’s parameters.
template <typename T, template <typename> class Container>
class Adapter {
    Container<T> underlyingContainer;
};

Default Template Arguments

Template parameters can have default types or values. Due to C++ scoping rules, a template parameter’s name is injected into scope immediately after its declaration. This allows subsequent default arguments to depend on previous parameters (e.g., template <typename T = int, typename U = std::vector<T>>). When instantiating a template, a user must omit arguments from right to left (an argument cannot be omitted unless all subsequent arguments are also omitted). However, the compiler evaluates and instantiates these omitted default arguments from left to right. This strict left-to-right evaluation guarantees that preceding parameters are fully resolved before they are utilized in subsequent default expressions.
#include <cstddef>

template <typename T = int, std::size_t Size = 100>
class DefaultBuffer {
    T buffer[Size];
};

// User omits arguments from right to left.
// Compiler evaluates and instantiates defaults from left to right (T=int, then Size=100).
DefaultBuffer<> defaultObj; 

Template Specialization

Specialization allows the programmer to override the primary template and provide a custom implementation for specific data types. Full (Explicit) Specialization Provides a completely distinct implementation for a specific set of template arguments. The template parameter list is left empty.
template <>
class ClassName<char> {
private:
    char memberVariable;
public:
    ClassName(char arg);
    bool isVowel() const; // Specialized behavior specific to 'char'
};
Partial Specialization Provides a specialized implementation for a subset of template arguments or for compound types (such as pointers or references) while leaving other parameters generic.
// Partial specialization for pointer types
template <typename T>
class ClassName<T*> {
private:
    T* pointerVariable;
public:
    ClassName(T* arg);
    T dereference() const;
};

Class Template Argument Deduction (CTAD)

Introduced in C++17, CTAD allows the compiler to deduce the template type parameters directly from the constructor arguments, eliminating the need to explicitly specify them during implicit instantiation.
template <typename T>
class Wrapper {
public:
    Wrapper(T value) {}
};

// Pre-C++17: Explicit type required
Wrapper<double> w1(3.14);

// C++17 and later: Type 'double' is deduced automatically
Wrapper w2(3.14); 

Compilation Model Constraints

Because the compiler requires the complete template definition to generate an instantiation, class template declarations and their member function definitions must typically reside in the same translation unit (usually the header file). If the implementation is separated into a .cpp file without explicit instantiation directives, it will result in linker errors (undefined reference).
Master C++ with Deep Grasping Methodology!Learn More