Lesson 35
Templates
Covers function templates, class templates, multiple template parameters, template type deduction, and template specialization.
Lesson content
What are templates in C++?
Templates are a C++ feature that allows you to write generic code. Instead of creating separate functions or classes for each data type, you create one template that works with many types.
Think of a template as a blueprint. Just as an architect creates one blueprint that can be used to build multiple houses with different colors or materials, a C++ template creates one piece of code that can work with different data types.
Instead of writing one function for int, another for double, another for float, and another for string, you write one template function.
Why do templates exist?
Without templates, code quickly becomes repetitive, such as writing addInt(), addFloat(), addDouble(), addLong(), and addChar() where each function performs the same operation. Templates eliminate this duplication by allowing one implementation to support multiple data types.
- Less code
- Easier maintenance
- Better readability
- Higher reusability
- Improved type safety
Real-world use cases
- Standard Template Library (STL)
- std::vector
- std::map
- std::set
- std::queue
- std::stack
- Smart pointers
- Generic sorting algorithms
- Mathematical libraries
- Game engines
- Database libraries
Prerequisites
- Variables
- Data types
- Functions
- Function overloading
- Classes and objects
- Basic object-oriented programming
- Basic STL usage (helpful but optional)
Why templates are needed
int max(int a, int b);
double max(double a, double b);
float max(float a, float b);
// The logic is identical.
// Templates remove this duplication.Function template syntax
template<typename T>
ReturnType functionName(T parameter);
// or
template<class T>
// Both typename and class mean the same thing in this context.Understanding template parameters
template<typename T>- template tells the compiler this is a template
- typename introduces a type parameter
- T is a placeholder for an actual data type
Later, T could become int, float, double, string, char, or a custom class.
Function templates
A function template creates functions automatically for different data types.
template<typename T>
T add(T a, T b)
{
return a + b;
}
// The compiler generates versions as needed.Class templates
Templates are not limited to functions. Entire classes can be generic.
template<typename T>
class Box
{
T value;
};Multiple template parameters
A template may use more than one type.
template<typename T, typename U>
// Useful when working with two unrelated types.Template type deduction
Usually, the compiler automatically determines the template type.
add(5,7);
// Compiler deduces:
// T = intExplicit template arguments
Sometimes you specify the type manually.
add<double>(5,6);Template specialization
Sometimes one type requires different behavior.
template<>
// This allows custom implementations.Example 1: Function template
#include <iostream>
using namespace std;
template<typename T>
T maximum(T a, T b)
{
return (a > b) ? a : b;
}
int main()
{
cout << maximum(5, 8) << endl;
cout << maximum(2.5, 8.9) << endl;
cout << maximum('A', 'Z') << endl;
return 0;
}
// Output:
// 8
// 8.9
// ZExample 2: Class template
#include <iostream>
using namespace std;
template<typename T>
class Box
{
private:
T value;
public:
Box(T v)
{
value = v;
}
void display()
{
cout << value << endl;
}
};
int main()
{
Box<int> b1(25);
Box<double> b2(6.78);
Box<string> b3("Hello");
b1.display();
b2.display();
b3.display();
return 0;
}Example 3: Multiple template parameters
#include <iostream>
#include <string>
using namespace std;
template<typename T, typename U>
class Pair
{
private:
T first;
U second;
public:
Pair(T a, U b)
{
first = a;
second = b;
}
void show()
{
cout << first << " " << second << endl;
}
};
int main()
{
Pair<int, string> student(101, "Alice");
student.show();
return 0;
}Example 4: Template specialization
#include <iostream>
using namespace std;
template<typename T>
class Printer
{
public:
void print(T value)
{
cout << value << endl;
}
};
template<>
class Printer<bool>
{
public:
void print(bool value)
{
if(value)
cout << "True" << endl;
else
cout << "False" << endl;
}
};
int main()
{
Printer<int> p1;
Printer<bool> p2;
p1.print(25);
p2.print(true);
return 0;
}Example 5: Generic swap function
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void swapValues(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int x = 10;
int y = 20;
swapValues(x, y);
cout << x << " " << y << endl;
string s1 = "Hello";
string s2 = "World";
swapValues(s1, s2);
cout << s1 << " " << s2 << endl;
return 0;
}Common mistakes and pitfalls
- Using different parameter types without matching template parameters. Fix: use multiple template parameters (template<typename T, typename U>) when needed
- Assuming templates work with every type automatically. Fix: ensure the type supports the required operations (such as +, <, or <<)
- Defining template implementations only in a .cpp file. Fix: place template definitions in headers or in the same translation unit so the compiler can instantiate them
- Overusing template specialization. Fix: prefer generic implementations and specialize only when behavior truly differs
- Ignoring compiler error messages. Fix: read template errors carefully, they often point to missing operations or type mismatches
// Wrong Code
template<typename T>
T add(T a, T b)
{
return a + b;
}
add(5, 6.2);
// Correct Code
template<typename T, typename U>
auto add(T a, U b)
{
return a + b;
}Best practices
- Keep template implementations as generic as possible
- Use meaningful template parameter names (T, Key, Value, Iterator) when appropriate
- Prefer typename for consistency in modern C++ code
- Keep template definitions in header files unless using explicit instantiation
- Use const references for large objects to avoid unnecessary copying
- Apply constraints (such as C++20 concepts) when a template should only accept certain kinds of types
- Avoid unnecessary template specialization; use it only when the generic implementation is insufficient
- Test templates with multiple data types to ensure they behave consistently
When not to use this
- Your code only ever needs one specific data type
- The behavior differs significantly for each type, making separate implementations clearer
- Compilation time is a concern in very large projects with heavy template usage
- Simpler techniques (such as function overloading) adequately solve the problem
- Readability suffers because the template becomes overly complex
Summary
- Templates in C++ enable generic programming by allowing one implementation to work with many data types
- They reduce code duplication and improve maintainability
- Function templates create generic functions
- Class templates create reusable classes for different types
- Multiple template parameters support combinations of different types
- Template argument deduction lets the compiler infer types automatically in many cases
- Template specialization customizes behavior for specific types
- Templates are the foundation of the Standard Template Library (STL)
- Keep templates generic, readable, and well-tested
- Use templates when they improve reuse, not simply because they are available
Frequently asked questions
What is the difference between typename and class in template declarations?
In template parameter lists, typename and class are equivalent. Most modern C++ code prefers typename because it more clearly indicates that the parameter represents a type.
Can templates work with user-defined classes?
Yes. Templates work with custom classes as long as those classes support the operations used by the template. For example, if a template compares values using <, your class should define an appropriate comparison operator.
Why are template definitions usually placed in header files?
The compiler must see the complete template definition whenever it needs to generate code for a specific type. Placing definitions in header files makes them available to every translation unit that includes the header.
What is template specialization?
Template specialization allows you to provide a custom implementation for a particular type while keeping the generic implementation for all other types. It's useful when one type requires different behavior.
Are templates slower than normal functions?
No. In most cases, templates generate type-specific code at compile time, so there is no runtime overhead compared to writing separate functions manually. In fact, templates often enable compiler optimizations that can improve performance.