Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

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:

  1. An int (e.g., clamp 150 between 0 and 100).
  2. A double (e.g., clamp -5.5 between -1.0 and 1.0).
  3. A float (e.g., clamp 0.5f between 0.0f and 1.0f).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.