C++ Function Templates

Generic functions that work with any data type

๐ŸŽฏ What are Function Templates?

Function templates create generic functions that work with multiple data types. Instead of writing separate functions for each type, templates generate them automatically.


// Template function works with any type
#include <iostream>
using namespace std;

template <typename T>
T getMax(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    cout << getMax(5, 3) << endl;        // Works with int
    cout << getMax(2.7, 1.9) << endl;    // Works with double
    cout << getMax('z', 'a') << endl;    // Works with char
    return 0;
}
                                    

Output:

5
2.7
z

Template Concepts

๐Ÿท๏ธ

Template Keyword

Declares a template function

template <typename T>
T myFunction(T param);
๐Ÿ”ค

Type Parameter

Placeholder for any data type

template <typename T>
// T can be int, double, etc.
โš™๏ธ

Automatic Deduction

Compiler determines the type

myFunction(5);    // T = int
myFunction(3.14); // T = double
๐Ÿ“‹

Multiple Types

Templates with multiple parameters

template <typename T, typename U>
void func(T a, U b);

๐Ÿ”น Basic Template Syntax

Function templates in C++ provide a blueprint for generating type-agnostic functions using the template <typename T> syntax. They allow a single function definition to work with multiple data types, promoting code reuse and reducing duplication. For example, a template add(T a, T b) can handle integers, doubles, and floats. Templates are resolved at compile-time, ensuring type safety and performance, and are foundational for generic programming in C++ libraries like STL.

#include <iostream>
using namespace std;

// Template declaration
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    // Compiler automatically deduces types
    cout << "Int addition: " << add(5, 3) << endl;
    cout << "Double addition: " << add(2.5, 3.7) << endl;
    cout << "Float addition: " << add(1.2f, 2.8f) << endl;
    
    // You can also explicitly specify the type
    cout << "Explicit int: " << add<int>(10, 20) << endl;
    
    return 0;
}

Output:

Int addition: 8
Double addition: 6.2
Float addition: 4
Explicit int: 30

๐Ÿ”น Multiple Template Parameters

Templates can define multiple type parameters to handle functions requiring several generic types. For example, template <typename T1, typename T2> allows pairs of different types, useful in containers, utility functions, or operations like max() comparing mixed types. This extends flexibility, supports heterogeneous data processing, and enables advanced generic patterns. Multiple template parameters are common in data structures (e.g., maps), algorithms, and adapter classes where type independence is crucial.

#include <iostream>
using namespace std;

// Template with two different types
template <typename T, typename U>
void printPair(T first, U second) {
    cout << "First: " << first << ", Second: " << second << endl;
}

// Template that returns the larger type
template <typename T, typename U>
auto getMax(T a, U b) -> decltype(a > b ? a : b) {
    return (a > b) ? a : b;
}

int main() {
    printPair(42, "Hello");
    printPair(3.14, 'A');
    printPair("World", 100);
    
    cout << "Max of 5 and 3.7: " << getMax(5, 3.7) << endl;
    cout << "Max of 2.1 and 8: " << getMax(2.1, 8) << endl;
    
    return 0;
}

Output:

First: 42, Second: Hello
First: 3.14, Second: A
First: World, Second: 100
Max of 5 and 3.7: 5
Max of 2.1 and 8: 8

๐Ÿ”น Practical Template Examples

Real-world template examples include generic swap, min/max, and array printing functions that work across types. A template swap(T& a, T& b) exchanges values of any type, while printArray(T arr[], int size) displays arrays of integers, doubles, etc. These examples demonstrate templatesโ€™ power in creating reusable, type-safe utilities. Practical use in algorithms, containers, and helpers reduces code bloat, enhances maintainability, and showcases C++โ€™s ability to write once, use everywhere.

#include <iostream>
using namespace std;

// Template for swapping values
template <typename T>
void swapValues(T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
}

// Template for finding minimum of three values
template <typename T>
T getMin(T a, T b, T c) {
    T min = a;
    if (b < min) min = b;
    if (c < min) min = c;
    return min;
}

// Template for array printing
template <typename T>
void printArray(T arr[], int size) {
    cout << "Array: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    // Swapping different types
    int x = 10, y = 20;
    cout << "Before swap: x = " << x << ", y = " << y << endl;
    swapValues(x, y);
    cout << "After swap: x = " << x << ", y = " << y << endl;
    
    double a = 5.5, b = 2.2;
    swapValues(a, b);
    cout << "Swapped doubles: a = " << a << ", b = " << b << endl;
    
    // Finding minimum
    cout << "Min of 5, 2, 8: " << getMin(5, 2, 8) << endl;
    cout << "Min of 3.7, 1.2, 9.1: " << getMin(3.7, 1.2, 9.1) << endl;
    
    // Printing arrays
    int intArr[] = {1, 2, 3, 4, 5};
    double doubleArr[] = {1.1, 2.2, 3.3};
    
    printArray(intArr, 5);
    printArray(doubleArr, 3);
    
    return 0;
}

Output:

Before swap: x = 10, y = 20
After swap: x = 20, y = 10
Swapped doubles: a = 2.2, b = 5.5
Min of 5, 2, 8: 2
Min of 3.7, 1.2, 9.1: 1.2
Array: 1 2 3 4 5
Array: 1.1 2.2 3.3

๐Ÿ”น Template Specialization

Template specialization allows custom implementations for specific types, overriding the generic template. For instance, a generic process() template might handle numbers, but a string specialization could compute length instead. This enables optimized or type-specific behavior while retaining a uniform interface. Specialization is useful for edge cases, performance tuning, or when certain types require unique logic, commonly seen in libraries, serialization, and type traits within C++ standard templates.

#include <iostream>
using namespace std;

// General template
template <typename T>
void process(T value) {
    cout << "Processing general type: " << value << endl;
}

// Specialized template for strings
template <>
void process<string>(string value) {
    cout << "Processing string (length " << value.length() << "): " << value << endl;
}

// Specialized template for char
template <>
void process<char>(char value) {
    cout << "Processing character: '" << value << "' (ASCII: " << (int)value << ")" << endl;
}

int main() {
    process(42);           // Uses general template
    process(3.14);         // Uses general template
    process("Hello");      // Uses string specialization
    process('A');          // Uses char specialization
    
    return 0;
}

Output:

Processing general type: 42
Processing general type: 3.14
Processing string (length 5): Hello
Processing character: 'A' (ASCII: 65)

๐Ÿง  Test Your Knowledge

What keyword is used to declare a function template?