Function Templates
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 64 of 104.
Imagine writing a function to find the maximum of two integers, then realizing you need the same logic for doubles, and again for strings. Without templates, you'd write nearly identical functions for each type. Function templates solve this by letting you write the logic once and have the compiler generate type-specific versions automatically.
A function template uses the template keyword followed by template parameters in angle brackets:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << maximum(5, 3) << std::endl; // Uses int version
std::cout << maximum(3.14, 2.71) << std::endl; // Uses double version
std::cout << maximum('a', 'z') << std::endl; // Uses char version
}The compiler examines each call and generates a concrete function for that specific type. This process is called template instantiation. You can also explicitly specify the type when needed:
std::cout << maximum<double>(5, 3.14) << std::endl; // Forces double versionTemplates can have multiple type parameters, enabling even more flexible designs:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*
printPair(3.14, 100); // T=double, U=intFunction templates provide compile-time polymorphism - the type is determined when the code is compiled, not at runtime. This means zero runtime overhead compared to virtual functions, making templates ideal for performance-critical generic code.
Challenge
EasyLet's build a utility toolkit using function templates to create reusable operations that work with any compatible type. You'll organize your generic functions in a header file and demonstrate their flexibility in your main program.
You'll create two files:
MathUtils.h: Define a collection of function templates that perform common operations:minimum— a template function that takes two values of the same type and returns the smaller one.clamp— a template function that takes three parameters: a value, a low bound, and a high bound. It returns the value constrained within the bounds (returns low if value is less than low, high if value is greater than high, otherwise returns the value itself).swapValues— a template function that takes two references of the same type and exchanges their values.main.cpp: Read six inputs (each on a separate line):- First integer
- Second integer
- A double value to clamp
- Low bound (double)
- High bound (double)
- A character
Demonstrate your templates by:
- Finding the minimum of the two integers and printing:
Min of <a> and <b>: <result> - Finding the minimum of the characters
'm'and your input character, printing:Min of m and <char>: <result> - Clamping the double value and printing:
Clamp <value> to [<low>, <high>]: <result> - Clamping the first integer to the range [0, 100] and printing:
Clamp <value> to [0, 100]: <result> - Swapping the two integers and printing:
After swapValues: <a>, <b>
For example, with inputs 25, 10, 3.7, 1.0, 5.0, and z:
Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25Notice how each template function works seamlessly with integers, doubles, and characters — the compiler generates the appropriate version for each type you use. Your swapValues function should modify the original variables through references, demonstrating that templates work with reference parameters just like regular functions.
Cheat sheet
Function templates allow you to write generic functions that work with multiple types. Use the template keyword followed by template parameters:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}The compiler automatically generates type-specific versions through template instantiation:
maximum(5, 3); // Generates int version
maximum(3.14, 2.71); // Generates double version
maximum('a', 'z'); // Generates char versionYou can explicitly specify the type when needed:
maximum<double>(5, 3.14); // Forces double versionTemplates support multiple type parameters:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*Templates work with reference parameters for modifying original values:
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}Function templates provide compile-time polymorphism with zero runtime overhead, making them ideal for performance-critical generic code.
Try it yourself
#include <iostream>
#include "MathUtils.h"
using namespace std;
int main() {
// Read inputs
int a, b;
double value, low, high;
char ch;
cin >> a;
cin >> b;
cin >> value;
cin >> low;
cin >> high;
cin >> ch;
// TODO: Use the minimum template to find min of two integers
// Print: "Min of <a> and <b>: <result>"
// TODO: Use the minimum template to find min of 'm' and input character
// Print: "Min of m and <char>: <result>"
// TODO: Use the clamp template on the double value
// Print: "Clamp <value> to [<low>, <high>]: <result>"
// TODO: Use the clamp template on the first integer with range [0, 100]
// Print: "Clamp <value> to [0, 100]: <result>"
// TODO: Use the swapValues template on the two integers
// Print: "After swapValues: <a>, <b>"
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container