C/C++
C++ Templates: Functions and Classes Guide

C++ templates let you write one function or class that compiles correctly for any data type you pass it. That single blueprint replaces what would otherwise be dozens of near-identical overloads. This guide covers function templates, class templates, template arguments, template metaprogramming, and how all of it connects to the Standard Template Library. Need hands-on help with a C++ assignment? Our team at C++ Programming Assignment Help works through template problems daily.
Templates enable generic programming: algorithms and data structures that stay type-independent. Instead of writing a separate sort for int, double, and std::string, you write one template and the compiler generates the correct version for each type at compile time.
Function Templates in C++
Function templates let you write a generic function once and call it with different types. The compiler generates a concrete version for each type you actually use.
The syntax uses the template keyword followed by a parameter list in angle brackets. Inside the list, typename T (or equivalently class T) declares a type placeholder you can use anywhere in the function signature and body.
Here is a function template that returns the larger of two values:
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
T stands for any type the caller provides. Call max(3, 7) and the compiler generates an int version. Call max(3.14, 2.71) and it generates a double version. No duplicate code.
The main payoff is reuse. One function template handles int, float, and any custom type that defines operator>, all without copying the function body.
Class Templates in C++
Class templates apply the same idea to entire classes. You define the class once using a type parameter, and the compiler generates a concrete class for each type you instantiate it with.
Basic syntax:
template <typename T>
class MyTemplate {
// Class definition using T
};
A practical example: a container that holds a single element of any type.
template <typename T>
class MyContainer {
private:
T element;
public:
void setElement(const T& value) {
element = value;
}
T getElement() const {
return element;
}
};
Write MyContainer<int> box; and the compiler produces a version where T is int throughout. Write MyContainer<std::string> box; and you get a std::string version. Same class definition, two distinct compiled types.
Template Specialization
Template specialization gives a specific type its own implementation instead of the generic one. Use it when the default behavior is wrong or inefficient for a particular type.
Example: a Print template that adds quotation marks around std::string values but not around other types.
template <typename T>
void Print(const T& value) {
std::cout << value << std::endl;
}
template <>
void Print(const std::string& value) {
std::cout << "\"" << value << "\"" << std::endl;
}
When you call Print with a std::string, the compiler picks the specialized version. Every other type uses the generic version.

Template Arguments
Template arguments control what the compiler generates from a template. They come in two varieties: type arguments and non-type arguments.
Type arguments name a data type. You supply them explicitly (Container<int>) or let the compiler deduce them from the call arguments. The typename or class keyword declares a type parameter in the template list.
Non-type arguments pass a constant value into the template rather than a type. Integers, characters, and pointers all work, provided the value is known at compile time. A common use is baking a fixed size into a container class:
template <typename T, int N>
class Container {
// T is the element type, N is the maximum size
};
Container<int, 10> myContainer; // holds up to 10 ints
Here int is the type argument and 10 is the non-type argument. The compiler produces a Container class specific to those two values.
Rules to keep in mind: non-type arguments must be compile-time constants, and the number and types of arguments must match the template's parameter list exactly.
Template Metaprogramming (TMP)
Template metaprogramming runs computations at compile time by exploiting the compiler's template instantiation mechanism. The result is code that executes with zero runtime overhead for those computations.
A classic example is computing a factorial at compile time through recursive template instantiation:
template <int N>
struct Factorial {
static constexpr int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static constexpr int value = 1;
};
The compiler expands Factorial<5>::value into 5 * 4 * 3 * 2 * 1 * 1 during compilation. No function call happens at runtime.
TMP also supports conditional code generation through specialization. The following detects whether a type is a pointer:
template <typename T>
struct IsPointer {
static constexpr bool value = false;
};
template <typename T>
struct IsPointer<T*> {
static constexpr bool value = true;
};
IsPointer<int>::value is false; IsPointer<int*>::value is true. The compiler resolves which specialization applies at compile time, so no branch exists in the final binary.
TMP is powerful but can produce error messages that are difficult to read. Keep TMP code small and well-commented. Most compile-time type logic you need today is already in the <type_traits> header.

Standard Template Library (STL)
The Standard Template Library (STL) is the payoff for learning C++ templates. It ships a set of generic containers and algorithms that work with any type that meets their requirements.
Templates are the STL's foundation. std::vector<int>, std::map<std::string, int>, and std::sort are all templates. You get a type-safe, zero-overhead container for any element type without writing a single line of container code yourself.
A minimal std::vector example:
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers;
numbers.push_back(42);
numbers.push_back(77);
numbers.push_back(13);
for (const auto& num : numbers) {
std::cout << num << " ";
}
return 0;
}
Include <iostream> and <vector>, declare std::vector<int> for a vector of integers, then add elements with push_back(). Swap <int> to <std::string> and the same code works for strings. The template does the work; you just pick the type.
Generic algorithms in the STL (std::sort, std::find, std::accumulate) take iterators and work on any compatible container. Sorting a std::vector<int> and sorting a std::list<std::string> use the same algorithm call.
Best Practices for C++ Templates
Templates are worth using carefully. A few guidelines save significant debugging time.
Put template definitions in header files. The compiler needs the full template definition when it instantiates a type. If the definition lives in a .cpp file and you include only the declaration, the linker will fail. Keep declarations and definitions together in the header.
Limit template bloat. Each unique combination of template arguments produces a separate compiled version. A template used with 20 different types generates 20 compiled copies. Keep template bodies small; move non-type-dependent logic into regular functions.
Use static_assert and concepts (C++20) to catch misuse early. Rather than letting the compiler produce a wall of template instantiation errors, add a static_assert at the top of the template body to check preconditions. In C++20, concepts express constraints directly in the template parameter list.
Avoid deep template recursion for ordinary tasks. Recursive TMP is expressive but produces long compile-time chains and cryptic errors. For most logic, constexpr functions (C++11 and later) are easier to read and debug.
For more on structuring templates alongside other C++ patterns, see Object-Oriented Programming in C++ Demystified and Smart Pointers in C++.
Conclusion
C++ templates eliminate duplicated code by letting you write one function or class that the compiler adapts for any type. Function templates handle operations across different types; class templates build type-independent data structures; template specialization handles the exceptions; TMP moves computation to compile time; and the STL gives you a production-grade library built entirely on this mechanism.
Start with function templates, use class templates when you need generic containers or policies, and lean on the STL before writing your own. Templates are the feature that makes C++ generic code both type-safe and zero-cost at runtime.
Related articles
- C/C++
Min Heap and Max Heap in C++
Build min heaps and max heaps in C++ with std::priority_queue and the STL heap algorithms, plus array math, heapify, heap sort, and worked examples.
Sep 19, 2023
- C/C++
Python vs C++: Which Should You Learn?
A direct comparison of Python and C++ across syntax, speed, memory management, OOP, and use cases to help you pick the right language.
Sep 17, 2023
- C/C++
Vectors in C++: A Complete Guide
Master std::vector in C++ with declaration, push_back and emplace_back, iterators, size vs capacity, 2D vectors, custom types, and complexity, with code that compiles.
Aug 7, 2023


