READMEC++

README

Templates / Class Templates

Concept Lesson
Intermediate
4 min

Learning Objective

Understand Templates well enough to explain it, recognize it in C++, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

Table Of ContentsBasic Class TemplatesMember FunctionsInside ClassOutside Class
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

README
2 min read17 headings

Class Templates in C++

Class templates let one class definition work with many types while preserving compile-time type checking. The main idea is simple: write the container or algorithm once, then let the compiler generate a concrete version such as Box<int>, Box<string>, or Array<double, 100> when the program uses it.

Use class templates when the behavior is the same but the stored type changes. Do not use them just to avoid thinking about design; if two types need different behavior, specialization or separate classes may be clearer.

Table of Contents


Basic Class Templates

template<typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T get() const { return value; }
    void set(T v) { value = v; }
};

Box<int> intBox(42);
Box<string> strBox("Hello");
Box<double> dblBox(3.14);

Member Functions

Inside Class

template<typename T>
class Stack {
    vector<T> data;
public:
    void push(const T& value) {
        data.push_back(value);
    }

    T pop() {
        T top = data.back();
        data.pop_back();
        return top;
    }

    bool empty() const {
        return data.empty();
    }
};

Outside Class

template<typename T>
class MyClass {
    T value;
public:
    MyClass(T v);
    T getValue() const;
    void setValue(T v);
};

template<typename T>
MyClass<T>::MyClass(T v) : value(v) {}

template<typename T>
T MyClass<T>::getValue() const { return value; }

template<typename T>
void MyClass<T>::setValue(T v) { value = v; }

Non-Type Parameters

template<typename T, size_t Size>
class Array {
    T data[Size];
public:
    T& operator[](size_t i) { return data[i]; }
    const T& operator[](size_t i) const { return data[i]; }
    constexpr size_t size() const { return Size; }
};

Array<int, 10> arr;
arr[0] = 42;

// Size is compile-time constant
Array<double, 100> bigArr;

Default Template Arguments

template<typename T = int, size_t Size = 10>
class Buffer {
    T data[Size];
public:
    size_t size() const { return Size; }
};

Buffer<> buf1;              // int, size 10
Buffer<double> buf2;        // double, size 10
Buffer<char, 256> buf3;     // char, size 256

Static Members

Each instantiation has its own static members:

template<typename T>
class Counter {
public:
    static int count;
    Counter() { ++count; }
    ~Counter() { --count; }
};

template<typename T>
int Counter<T>::count = 0;

Counter<int> a, b, c;
cout << Counter<int>::count;     // 3

Counter<double> d;
cout << Counter<double>::count;  // 1 (separate counter!)

Template Specialization

Full Specialization

// Primary template
template<typename T>
class Printer {
public:
    void print(const T& value) {
        cout << value << endl;
    }
};

// Specialization for bool
template<>
class Printer<bool> {
public:
    void print(const bool& value) {
        cout << (value ? "true" : "false") << endl;
    }
};

Partial Specialization

// Primary template
template<typename T>
class Container {
    T value;
public:
    void show() { cout << "Value: " << value << endl; }
};

// Partial specialization for pointers
template<typename T>
class Container<T*> {
    T* ptr;
public:
    void show() { cout << "Pointer to: " << *ptr << endl; }
};

Best Practices

✅ Do

// 1. Keep template code in headers
// myclass.h
template<typename T>
class MyClass {
    // Full implementation here
};

// 2. Use typename for dependent types
template<typename T>
class Container {
    typename T::value_type item;  // T::value_type is a type
};

// 3. Provide type aliases
template<typename T>
class MyContainer {
public:
    using value_type = T;
    using size_type = size_t;
};

❌ Don't

// 1. Don't separate template implementation
// WON'T LINK:
// header.h: template<typename T> class C { void f(); };
// source.cpp: template<typename T> void C<T>::f() { }

// 2. Don't assume T has specific operations
template<typename T>
class Bad {
    void sort() { /* assumes T is sortable */ }
};

Quick Reference

// Basic class template
template<typename T>
class MyClass { T data; };

// Multiple parameters
template<typename T, typename U>
class Pair { T first; U second; };

// Non-type parameter
template<typename T, size_t N>
class Array { T data[N]; };

// Default arguments
template<typename T = int>
class Default { };

// Member outside class
template<typename T>
void MyClass<T>::method() { }

// Full specialization
template<>
class MyClass<int> { };

// Partial specialization
template<typename T>
class MyClass<T*> { };

Compile & Run

Learner Notes

The most important rule is that template code usually needs to be visible at the point where it is instantiated. That is why template class definitions often live in header files instead of only in .cpp files. If the linker says it cannot find a template member function, the implementation may be hidden from the translation unit that needs it.

Read a class template in three passes. First, identify the template parameters: typename T, non-type parameters such as size_t Size, and any defaults. Second, inspect which members depend on those parameters. Third, check how the class behaves for edge cases such as pointers, const objects, and empty containers.

Practice by turning a normal Stack<int> into Stack<T>, then instantiate it with int, string, and a custom struct. If all three versions compile and the public API still makes sense, the template is probably shaped well.

g++ -std=c++17 -Wall examples.cpp -o examples && ./examples

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue