Function Templates — Template Parameters, Type Deduction, Overloading
In this tutorial, you will learn about Function Templates. We cover key concepts, practical examples, and best practices to help you master this topic.
C++ function templates allow writing a single function definition that works with any data type, with the compiler instantiating type-specific versions automatically at compile time.
What You'll Learn
You will write function templates with template type parameters and non-type parameters, understand template argument deduction and explicit instantiation, overload templates with regular functions and other templates, separate template declarations from definitions, and apply SFINAE-friendly patterns in overload resolution.
Why It Matters
Without templates, you would need to write separate overloads for every type: int max(int, int), double max(double, double), string max(string, string). A single function template replaces them all while preserving type safety. Templates are the foundation of generic programming in C++, used throughout the standard library and in every modern C++ codebase.
Learning Path
graph LR
A["41: Iterator Types"] --> B["42: Function Templates"]
B --> C["43: Class Templates"]
C --> D["44: Template Specialization"]
style A fill:#4a90d9,stroke:#2c5f8a,color:#fff
style B fill:#4a90d9,stroke:#2c5f8a,color:#fff
style C fill:#4a90d9,stroke:#2c5f8a,color:#fff
style D fill:#4a90d9,stroke:#2c5f8a,color:#fff
Basic Function Template
A function template starts with the template keyword followed by template parameters in angle brackets.
#include <iostream>
#include <string>
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// Compiler deduces T = int
std::cout << max(3, 7) << "\n"; // 7
// T = double
std::cout << max(3.14, 2.72) << "\n"; // 3.14
// T = std::string
std::cout << max(std::string("apple"), std::string("orange")) << "\n"; // orange
// Explicit type specification
std::cout << max<double>(3, 7.5) << "\n"; // 7.5
}
The compiler generates three separate functions: one for int, one for double, and one for std::string. Each is type-specific with zero runtime overhead.
Multiple Template Parameters
You can have multiple type parameters and mix type with non-type parameters.
#include <iostream>
#include <type_traits>
template <typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
// Non-type template parameter (value parameter)
template <typename T, int Size>
T multiplyBySize(T value) {
return value * Size;
}
int main() {
auto result = add(3, 4.5);
std::cout << result << "\n"; // 7.5
std::cout << multiplyBySize<int, 10>(5) << "\n"; // 50
std::cout << multiplyBySize<double, 3>(2.5) << "\n"; // 7.5
}
Non-type parameters must be compile-time constants: integers, enumerations, pointers, references, or std::nullptr_t.
Template Argument Deduction
The compiler deduces template arguments from the function arguments. Understanding deduction rules prevents surprises.
#include <iostream>
#include <string>
template <typename T>
void deduce(T a, T b) {
std::cout << a << " " << b << "\n";
}
// Reference deduction preserves reference-ness
template <typename T>
void ref_deduce(T& a) {
// T is deduced without reference
}
// Forwarding reference (T&&) is special
template <typename T>
void forward_deduce(T&& a) {
// T = int& for lvalue, int for rvalue
}
int main() {
deduce(1, 2); // OK, T = int
// deduce(1, 2.5); // Error: conflicting types (int vs double)
int x = 5;
ref_deduce(x); // T = int (not int&)
forward_deduce(5); // T = int
forward_deduce(x); // T = int& (special forwarding reference case)
}
Overloading with Templates
Templates participate in overload resolution with regular functions and other templates.
#include <iostream>
#include <cstring>
// 1. Regular function
void print(const char* s) {
std::cout << "char*: " << s << "\n";
}
// 2. Template function
template <typename T>
void print(const T& value) {
std::cout << "template: " << value << "\n";
}
// 3. More specialized template
template <typename T>
void print(T* ptr) {
std::cout << "pointer template: " << *ptr << "\n";
}
int main() {
print("hello"); // Exact match: calls #1 (char*)
print(42); // Calls #2 (template, T = int)
int x = 10;
print(&x); // Calls #3 (pointer template, T = int)
const char* msg = "world";
print(msg); // Calls #1 (exact match beats template)
}
Overload resolution prefers non-template functions over templates when both are equally good matches. Among templates, more specialized ones are preferred.
Separating Declaration and Definition
For function templates, the full definition must be visible at the point of instantiation. The common approach is to put everything in a header file.
// In header file (max.h)
#ifndef MAX_H
#define MAX_H
template <typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// Explicit instantiation declaration (C++11)
extern template int max(int, int);
#endif
// In one translation unit (max.cpp)
template int max(int, int); // explicit instantiation definition
Without explicit instantiation, the compiler instantiates templates in every translation unit that uses them, potentially increasing compile times and binary size.
Common Mistakes
Mistake 1: Putting template definitions in .cpp files
// header.h
template <typename T>
T max(T a, T b); // declaration only
// header.cpp
template <typename T>
T max(T a, T b) { return (a > b) ? a : b; }
The linker cannot find the definition when another file instantiates the template. Always keep definitions in headers.
Mistake 2: Assuming type conversion
template <typename T>
T max(T a, T b);
max(3, 7.5); // Error: conflicting deduction (int vs double)
Use explicit arguments: max<double>(3, 7.5) or make the template accept two types.
Mistake 3: Forgetting typename for dependent types
template <typename T>
void example() {
T::iterator it; // Error: need 'typename T::iterator'
typename T::iterator it2; // OK
}
Mistake 4: Passing by value for large types
template <typename T>
T max(T a, T b); // Copies large objects
Use forwarding references or const T& when objects are expensive to copy.
Mistake 5: Overlooking ODR violations with inline
// In two translation units
template <typename T>
void func(T) {}
// OK: templates have implicit inline linkage
But if two files define the same non-template function, that violates ODR.
Practice Questions
- What is the output?
template <typename T>
T square(T x) { return x * x; }
int main() {
std::cout << square(5) << " " << square(2.5);
}
Answer: 25 6.25 — compiler deduces int and double.
Why does
max(3, 7.5)fail to compile? Answer: Template argument deduction finds conflicting types (intvsdouble). Usemax<double>(3, 7.5)or two type parameters.What is the difference between
template <typename T>andtemplate <class T>? Answer: They are identical.typenameis preferred since C++98 to avoid confusion with class types.Can a non-type template parameter be a
doubleorstd::string? Answer: Only integral types, enumerations, pointers, references, andstd::nullptr_t. Floating-point and class types are not allowed.Write a function template that returns the smaller of two values.
template <typename T>
T min(T a, T b) { return (a < b) ? a : b; }
FAQ
Mini Project
Write a generic print_container function template that works with any iterable container (vector, list, set, array, map) and prints its elements separated by commas:
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <map>
// Your print_container template here
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
print_container(v); // 1, 2, 3, 4, 5
std::set<std::string> s = {"apple", "banana", "cherry"};
print_container(s); // apple, banana, cherry
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
print_container(m); // 1: one, 2: two
}
This exercise reinforces template parameter deduction, Iterator usage, and generic programming — the foundation of the C++ STL.
What's Next
Now you understand function templates, the foundation of generic programming. Next, you will extend these concepts to entire classes in C++ class templates. For a broader perspective on static typing, compare with Java generics which use type erasure instead of template instantiation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro