Ready to practice?
Sign up to access interactive coding exercises and track your progress.
Generic Types with Class Templates
Create structs and classes that work with any data type using templates.
The type repetition problem
Suppose you're building a game inventory system that tracks item quantities:
struct IntSlot
{
int item{};
int quantity{};
};
This works for items identified by integer IDs. But your UI needs string-based item names:
struct StringSlot
{
std::string item{};
int quantity{};
};
Now you have two nearly identical structs. Adding support for item enums means a third. The pattern repeats: same structure, different types.
Class templates solve this
A class template is a blueprint for generating struct and class definitions. You define the pattern once, and the compiler creates specialized versions for each type you need.
template <typename T>
struct Slot
{
T item{};
int quantity{};
};
Now you can create slots holding any item type:
Slot<int> byId{ 42, 5 }; // item is int
Slot<std::string> byName{ "sword", 1 }; // item is std::string
Defining a class template
Start with the template parameter declaration, then define the struct using the placeholder type:
template <typename T>
struct Container
{
T value{};
bool hasValue{ false };
};
The syntax mirrors function templates:
template <typename T>declares the placeholder typeTcan be used wherever you need a flexible type- Members can mix template and concrete types
Instantiating class templates
Specify the type in angle brackets when creating objects:
#include <iostream>
#include <string>
template <typename T>
struct Container
{
T value{};
bool hasValue{ false };
};
int main()
{
Container<int> count{ 42, true };
Container<double> measurement{ 98.6, true };
Container<std::string> message{ "Hello", true };
std::cout << count.value << '\n'; // 42
std::cout << measurement.value << '\n'; // 98.6
std::cout << message.value << '\n'; // Hello
return 0;
}
The compiler generates three distinct types:
Container<int>with anint valuememberContainer<double>with adouble valuememberContainer<std::string>with astd::string valuemember
What the compiler generates
When you write:
Container<int> count{ 42, true };
The compiler produces something equivalent to:
struct Container_int
{
int value{};
bool hasValue{ false };
};
Container_int count{ 42, true };
Each unique template argument creates one type definition. Container<int> and Container<double> are completely separate types that happen to share a structural pattern.
Using class templates with function templates
Class templates often pair with function templates:
#include <iostream>
template <typename T>
struct Range
{
T low{};
T high{};
};
template <typename T>
T midpoint(Range<T> r)
{
return (r.low + r.high) / 2;
}
int main()
{
Range<int> scores{ 0, 100 };
Range<double> temperatures{ -40.0, 120.0 };
std::cout << midpoint(scores) << '\n'; // 50
std::cout << midpoint(temperatures) << '\n'; // 40
return 0;
}
The function template's T matches the class template's T, allowing seamless type deduction.
Multiple template parameters
Class templates can have multiple type parameters:
template <typename K, typename V>
struct Entry
{
K key{};
V value{};
};
Usage:
Entry<int, std::string> userById{ 1001, "Alice" };
Entry<std::string, double> priceByName{ "apple", 1.99 };
Entry<char, int> asciiValue{ 'A', 65 };
Each parameter resolves independently, allowing different combinations.
Functions accepting multi-parameter templates
Function templates working with multi-parameter class templates need matching declarations:
#include <iostream>
template <typename K, typename V>
struct Entry
{
K key{};
V value{};
};
template <typename K, typename V>
void display(Entry<K, V> e)
{
std::cout << e.key << " -> " << e.value << '\n';
}
int main()
{
Entry<std::string, int> score{ "Player1", 2500 };
display(score); // Player1 -> 2500
return 0;
}
Generic function parameters
Sometimes you want a function that works with any type having certain members:
template <typename T>
void showKeyValue(T item)
{
std::cout << item.key << ": " << item.value << '\n';
}
This works with any type that has key and value members, not just Entry:
struct Config
{
std::string key{};
int value{};
};
Entry<std::string, double> setting{ "volume", 0.75 };
Config option{ "maxPlayers", 8 };
showKeyValue(setting); // Works with Entry
showKeyValue(option); // Works with Config too
The standard library's std::pair
The standard library provides std::pair<T, U> for paired values:
#include <utility>
#include <iostream>
int main()
{
std::pair<std::string, int> player{ "Alice", 100 };
std::cout << player.first << ": " << player.second << '\n';
return 0;
}
Members are named first and second. Use std::pair instead of writing custom pair types.
Class templates in header files
Place class templates in headers for use across multiple files:
container.h:
#pragma once
template <typename T>
struct Container
{
T value{};
bool hasValue{ false };
};
template <typename T>
bool isEmpty(Container<T> c)
{
return !c.hasValue;
}
main.cpp:
#include "container.h"
#include <iostream>
int main()
{
Container<int> data{ 42, true };
std::cout << isEmpty(data) << '\n'; // 0 (false)
return 0;
}
Templates are exempt from the one-definition rule, so including them in multiple files works correctly.
Summary
| Concept | Syntax |
|---|---|
| Single-type template | template <typename T> struct Name { T member; }; |
| Multi-type template | template <typename T, typename U> struct Name { T a; U b; }; |
| Instantiation | Name<int> obj{ value }; |
| Function with template param | template <typename T> void func(Name<T> param) |
Key points:
- Class templates generate type definitions from a single pattern
- Each unique template argument set produces a distinct type
- Template parameters can mix with concrete types in the same struct
- Function templates naturally pair with class templates
std::pair<T, U>is the standard library's general-purpose pair type- Place templates in headers for multi-file usage
Generic Types with Class Templates - Quiz
Test your understanding of the lesson.
Practice Exercises
Generic Container Pair
Create a Pair class template that can hold two values of any type. Implement a function template that works with Pair objects.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!