C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
54: Function Templates
You've probably already noticed a frustrating pattern in your C++ code: you often write the exact same logic multiple times, just for different data types. Maybe you wrote a function to find the larger of two integers, and then you realized you needed the exact same logic for doubles, then floats, and maybe even long longs. It feels like a waste of time to copy-paste the same three lines of code just to change int to double.
The pain of repeating logic
Let's look at how I usually start these things. I want a simple utility function that returns the maximum of two values. My first instinct is the obvious one:
int maxValue(int a, int b) {
return (a > b) ? a : b;
}
That works great for integers. But the moment I try to pass it two doubles, the compiler starts complaining or, worse, it silently casts my doubles down to integers and gives me the wrong answer. I could write an overload for double, and another for float, but that's just bookkeeping. I'm not adding any new logic; I'm just satisfying the compiler's obsession with types.
Turning a specific function into a blueprint
This is where function templates come in. Instead of writing the function for a specific type, I'm going to write a blueprint. I'll tell C++, "Here is how the logic works; you figure out the type based on what I pass into it."
Here is how I'd rewrite that maxValue function as a template:
template <typename T>
T maxValue(T a, T b) {
return (a > b) ? a : b;
}
The template <typename T> line is the magic part. I'm introducing a placeholder called T. Whenever I call maxValue, the compiler looks at the arguments I provided and replaces every T in the function with the actual type. If I pass two ints, T becomes int. If I pass two strings, T becomes std::string (since strings can be compared with >).
When the compiler gets confused by mixed types
Now, I'll be honest—I've tripped over this specific issue more times than I'd like to admit. I tried to be clever and call my new template function with mixed types, thinking the compiler would just "figure it out."
int main() {
int x = 5;
double y = 2.5;
// I thought this would just work...
auto result = maxValue(x, y);
}
The compiler immediately threw a fit. The error message was something like "could not deduce template argument for 'T'". This happened because I told the compiler that both arguments must be the same type T. I passed an int and a double, and the compiler refused to guess which one I wanted the result to be. It doesn't want to make a decision about precision loss without my permission.
To fix this, I have two choices. I can cast one of the variables manually, or I can explicitly tell the function which type to use by specifying it in angle brackets:
// This tells the compiler: "Treat both as doubles"
auto result = maxValue<double>(x, y);
By adding <double>, I've removed the ambiguity. Now the compiler knows exactly how to handle the conversion.
Letting the compiler do the heavy lifting
The beauty of this approach is that my maxValue function now works for any type that supports the > operator. I didn't have to write a single line of code for floating point numbers or custom objects; I just defined the relationship. As a rule of thumb, if you find yourself writing three versions of the same function where only the type changes, stop and use a template.
📋 Practical Task
Building a Generic Value Clamper
In game development and signal processing, a "clamp" function is incredibly common. It ensures a value stays between a minimum and a maximum boundary. If the value is below the minimum, it returns the minimum; if it's above the maximum, it returns the maximum; otherwise, it returns the value itself.
Your Task: Create a function template called clampValue that takes three arguments of the same type T: value, min, and max. Implement the logic to return the clamped value.
Then, in your main function, demonstrate that it works by clamping:
- An
int(e.g., clamp 150 between 0 and 100). - A
double(e.g., clamp -5.5 between -1.0 and 1.0). - A
float(e.g., clamp 0.5f between 0.0f and 1.0f).
There are no comments for now.