Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

4.1 Function Templates & Class Templates

Lesson 19 of 22 in the free Object Oriented Programming with C++ notes on Siksha Sarovar, written by Rohit Jangra.

4.1 Function Templates & Class Templates

What is Generic Programming?

Generic programming writes algorithms and data structures independent of the data type they operate on. The same code works for int, double, string, user-defined types.

C++ achieves genericity via templates — a form of parametric polymorphism resolved at compile time.

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

add(3, 5);          // T = int
add(2.5, 3.5);      // T = double
add(string("Hi "), string("World"));  // T = string

The compiler generates one version per type — zero runtime cost.

---

Function Templates

A function template is a blueprint from which the compiler generates concrete functions when called with specific types.

Syntax

template<typename T>            // T is the template parameter
returnType name(parameters) {
    // body using T
}

typename and class are interchangeable here:

template<class T>     // same as typename

Example — generic max

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

int main() {
    cout << max(3, 5);                  // 5
    cout << max(2.5, 1.5);              // 2.5
    cout << max(string("apple"), string("banana"));  // banana
    return 0;
}

How template instantiation works

At each call site, the compiler:

  1. Deduces T from the argument types
  2. Instantiates a concrete function with T replaced
  3. Compiles that function
max(3, 5);
// Compiler generates:
// int max(int a, int b) { return (a > b) ? a : b; }

Multiple template parameters

template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {       // C++11 trailing return type
    return a + b;
}

add(3, 5.5);          // T=int, U=double, return = double

In C++14+, simpler:

template<typename T, typename U>
auto add(T a, U b) { return a + b; }

Explicit template argument

If type deduction fails or you want to force a type:

add<double>(3, 5);    // force T = double

---

Characteristics of Function Templates

PropertyDetail
One template, many functionsCompiler instantiates on demand
Type-deductionUsually automatic from arguments
Compile-timeAll resolution happens at compile time
Zero overheadNo runtime cost — like writing each version by hand
Each instantiation = full compileMore instantiations = more compile time + larger binary
Type must support required operationsIf T is used with >, T must have operator>

---

Overloading Template Functions

You can overload a template with a non-template, or specialise:

1. Non-template overload (takes precedence)

template<typename T>
void print(T x) { cout << "template: " << x << endl; }

void print(int x) { cout << "non-template int: " << x << endl; }  // overload

print(5);          // calls non-template int version (preferred)
print(5.5);         // calls template (T = double)
print('A');         // calls template (T = char)

2. Template specialisation (custom behaviour for specific type)

template<typename T>
void print(T x) { cout << "Generic: " << x << endl; }

template<>
void print<string>(string s) { cout << "String: \"" << s << "\"" << endl; }

print(5);                   // Generic
print(string("hello"));     // String: "hello"

3. Template overload with different parameter counts

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

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

add(1, 2);          // 2-arg version
add(1, 2, 3);       // 3-arg version

---

Class Templates

A class template parameterises a class by one or more types:

template<typename T>
class Box {
private:
    T content;

public:
    Box(T c) : content(c) {}
    T get() const { return content; }
    void set(T c) { content = c; }
};

int main() {
    Box<int>    intBox(42);
    Box<string> strBox("hello");
    Box<double> dblBox(3.14);

    cout << intBox.get() << endl;     // 42
    cout << strBox.get() << endl;     // hello
    return 0;
}

You must specify the type when instantiating: Box<int>, Box<string>.

Member functions defined outside the class

template<typename T>
class Stack {
private:
    T data[100];
    int top;

public:
    Stack();
    void push(T x);
    T pop();
};

// Implementation OUTSIDE the class — also a template
template<typename T>
Stack<T>::Stack() : top(-1) {}

template<typename T>
void Stack<T>::push(T x) {
    if (top < 99) data[++top] = x;
}

template<typename T>
T Stack<T>::pop() {
    return (top >= 0) ? data[top--] : T();
}

Each external definition needs its own template<typename T> declaration.

---

Class Template — Stack Example

template<typename T>
class Stack {
private:
    T* data;
    int size;
    int top;

public:
    Stack(int s) : size(s), top(-1) {
        data = new T[size];
    }

    ~Stack() { delete[] data; }

    void push(T x) {
        if (top + 1 < size) data[++top] = x;
        else cout << "Stack full\n";
    }

    T pop() {
        if (top >= 0) return data[top--];
        return T();   // default-constructed T
    }

    bool empty() const { return top == -1; }
    int  count() const { return top + 1; }
};

int main() {
    Stack<int> s(10);
    s.push(1); s.push(2); s.push(3);
    while (!s.empty()) cout << s.pop() << " ";   // 3 2 1
    cout << endl;

    Stack<string> ss(5);
    ss.push("Hello");
    ss.push("World");
    cout << ss.pop() << endl;    // World
    return 0;
}

One template, infinite type combinations.

---

Multiple Template Parameters

template<typename K, typename V>
class Pair {
public:
    K key;
    V value;

    Pair(K k, V v) : key(k), value(v) {}

    void display() const {
        cout << key << " => " << value << endl;
    }
};

int main() {
    Pair<string, int> age("Rohit", 25);
    age.display();    // Rohit => 25

    Pair<int, double> rate(101, 8.5);
    rate.display();   // 101 => 8.5
    return 0;
}

---

Default Template Arguments

template<typename T = int, int SIZE = 100>
class FixedArray {
    T data[SIZE];
public:
    T& operator[](int i) { return data[i]; }
};

FixedArray<>          a;     // T=int, SIZE=100
FixedArray<double>    b;     // T=double, SIZE=100
FixedArray<char, 50>  c;     // T=char, SIZE=50

---

Non-Type Template Parameters

Template parameters can be values (not just types):

template<int N>
class Array {
private:
    int data[N];
public:
    int& operator[](int i) { return data[i]; }
    int size() const { return N; }
};

Array<10> a;           // N = 10 — array of 10 ints
Array<100> big;        // N = 100
cout << a.size();       // 10

Allowed non-type parameters: integers, pointers, references, enum values — all known at compile time.

---

Template Specialisation

Sometimes you want different behaviour for a specific type:

Full specialisation

template<typename T>
class Print {
public:
    void operator()(T x) {
        cout << x << endl;
    }
};

template<>                       // full specialisation for bool
class Print<bool> {
public:
    void operator()(bool x) {
        cout << (x ? "true" : "false") << endl;
    }
};

Print<int> pi; pi(5);             // 5
Print<bool> pb; pb(true);         // true (not 1)

Partial specialisation (classes only — not functions)

template<typename T, typename U>
class Pair { /* general */ };

template<typename T>
class Pair<T, T> {                // partial — when both types are same
    /* special behaviour */
};

Pair<int, double> p1;      // general
Pair<int, int>    p2;      // partial specialisation

---

Templates vs Macros — exam classic

AspectMacros (#define)Templates
ResolutionPreprocessor — text substitutionCompiler — type-aware
Type safetyNoneStrong
Debugger supportHardNormal
Error messagesCryptic preprocessor errorsCompiler errors with template context
ScopeGlobal, no namespacingRespects scope
UseConditional compilation, legacyModern generic code

Modern C++ strongly prefers templates over macros.

---

Templates vs Function Overloading

AspectFunction OverloadingFunction Templates
Multiple functionsWritten by programmerGenerated by compiler
ImplementationEach version separatelySingle generic implementation
Code reuseLimitedExcellent
When to useDifferent behaviour per typeSame behaviour across types
ResolutionCompile-timeCompile-time

You can combine them — overload a template with a non-template (compiler prefers the non-template if it matches).

---

Templates Power the STL

The Standard Template Library (STL) is built entirely on templates:

vector<int>            ints;
vector<string>          words;
map<string, int>        counts;
set<double>             unique;
list<Student>           students;

All containers, algorithms (sort, find, accumulate), and iterators are templates. Zero-overhead generic data structures and algorithms.

---

Limitations of Templates

LimitationDetail
Long compile timesEach instantiation = full compile
Larger binariesEach unique T = separate compiled code
Hard error messagesPages of template-instantiation traces
All code in headersTemplate implementation must be visible to caller
Type T must support operations usedIf you write a > b, T must have >

---

Modern: auto and Concepts

C++14 — generic lambdas

auto add = [](auto a, auto b) { return a + b; };
add(1, 2);       // int
add(1.5, 2.5);   // double

C++20 — concepts (constrained templates)

template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

template<Numeric T>
T add(T a, T b) { return a + b; }

add(1, 2);           // OK
// add("a", "b");    // ERROR — string isn't Numeric

Concepts make template errors clean and intent obvious.

---

Study deep

  1. Templates are zero-cost. Each vector<int> is as fast as a hand-written int-array class. The cost is compile-time + binary size — never runtime.
  1. Header-only is a feature. Templates live in headers because the compiler needs the full definition to instantiate. This is why STL is in headers.
  1. Template metaprogramming (TMP) is a Turing-complete language. Crazy power: compute factorials at compile time, generate code based on types. Used heavily in performance-critical libraries (Boost, Eigen, expression templates).
  1. Type deduction is mostly intuitive. max(1, 2)T = int. max(1, 2.0) → ERROR (ambiguous). Forcing with max<double>(1, 2.0) resolves it.
  1. Don't fear template error messages. They look intimidating but always trace back to: "on this line, you used T as if it had this operation, but the actual type doesn't". Read the bottom of the error stack, not the top.

Key Terms — Lesson 4.1

The terms below cover C++ templates — every PYQ on function/class templates or generic programming expects fluent use.

Generic Programming — Writing code that works for any type, deferring the type choice to the user. C++ implements generic programming via templates. std::sort works on int, string, custom classes — the algorithm is written once.

Template — A C++ construct that parameterises code on one or more types or values. Templates are compile-time blueprints; the compiler instantiates concrete code from the template each time it is used with specific arguments.

Function Template — A template that produces a function for each set of type arguments. template<typename T> T max(T a, T b) { return a > b ? a : b; } — the compiler generates max<int>, max<double>, etc., as needed.

Class Template — A template that produces a class for each set of type arguments. template<typename T> class Stack { ... };Stack<int> and Stack<string> are two different (compiler-generated) classes with the same structure.

Template Parameter — The placeholder type or value in a template declaration. Type parameter (typename T or class T) holds a type. Non-type parameter (int N, size_t size) holds a value. C++20 also adds type-constrained parameters via concepts.

typename vs class (in Templates) — Two equivalent keywords for declaring type parameters: template<typename T> and template<class T> mean the same thing. typename is preferred in modern style; class is the older keyword.

Template Instantiation — The compiler's process of generating concrete code from a template when it sees a use like vector<int>. The compiler substitutes the type arguments and compiles the resulting concrete class or function. Each unique combination of arguments produces one instantiation.

Implicit Instantiation — The compiler automatically instantiates a template the first time it sees the template used with specific arguments. max(1, 2) triggers instantiation of max<int>.

Explicit Instantiation — A way to tell the compiler to instantiate a template at a specific point even without a use: template int max<int>(int, int);. Used to control where template code appears in the binary and to reduce duplicated instantiations across translation units.

Type Deduction — The compiler's algorithm for inferring template arguments from the call. max(1, 2) infers T = int. max(1, 2.0) is ambiguous; max<double>(1, 2.0) resolves it explicitly.

Template Specialisation — Providing a custom implementation for a specific type or set of types: template<> void print<bool>(bool b) overrides the generic print<T> for bool only. Full specialisation handles a single combination; partial specialisation handles a pattern (works for class templates).

Variadic Template (C++11) — A template that takes a variable number of arguments. template<typename... Args> declares a parameter pack. Used to implement std::make_unique, printf-style formatting (std::format), tuple, etc.

Parameter Pack / Pack Expansion — A template-parameter pack typename... Args can be expanded using Args... syntax to apply each argument in turn. The mechanism behind variadic templates.

STL (Standard Template Library) — The C++ standard library's collection of template-based containers, algorithms, and iterators: vector, list, map, set, sort, find, accumulate, etc. Designed by Alexander Stepanov; merged into the C++ standard in 1998.

Container (STL) — A template class that holds a collection of elementsvector<T>, list<T>, map<K, V>, set<T>, unordered_map, etc. Containers manage memory automatically (RAII).

Iterator (STL) — A template-based "pointer abstraction" over a container. Iterators support ++ (advance), * (dereference), == (compare). Algorithms operate on iterator ranges, decoupling them from the container type.

Algorithm (STL) — A template function that operates on iterator rangesstd::sort, std::find, std::accumulate, std::transform. Algorithms know nothing about the container; they just consume iterators. The genius of the STL: container × algorithm decoupling.

Concept (C++20) — A compile-time predicate on types, used to constrain template parameters. template<std::integral T> requires T to satisfy the integral concept. Concepts make template errors clean, document intent, and replace SFINAE in many cases.

SFINAE (Substitution Failure Is Not An Error) — A C++ idiom: when template type substitution fails, the compiler silently removes the candidate from overload resolution rather than emitting an error. Used heavily pre-C++20 for type-based dispatching; largely replaced by concepts in modern C++.

Template Metaprogramming (TMP) — Using templates to perform computation at compile time — compute factorials in types, generate code based on type traits, optimise away abstractions. TMP is Turing-complete; used in performance-critical libraries (Boost, Eigen).

Type Trait — A template-based compile-time query about a typestd::is_integral<T>, std::is_pointer<T>, std::is_base_of<Base, Derived>. Used to enable/disable templates based on type characteristics. Standardised in <type_traits>.

auto Keyword (C++11) — Lets the compiler deduce a variable's type from its initialiser. auto v = vector<int>{1, 2, 3};. Reduces verbosity in template-heavy code where types can be long. auto is type deduction at the variable level; templates are type deduction at the function/class level.

Lambda Expression (C++11) — An inline anonymous function with optional capture: auto add = [](int a, int b) { return a + b; };. Lambdas are conceptually functors generated by the compiler. C++14 added generic lambdas with auto parameters.

Zero-Overhead Abstraction — A C++ principle (Stroustrup): abstractions should cost nothing at runtime beyond what manually-written code would. Templates exemplify this — std::vector<int> is as fast as a hand-written int-array class.

Header-Only Library — A library whose entire implementation lives in header files, with no separate .cpp compilation. Template code typically must be in headers (the compiler needs to see definitions to instantiate). Most modern C++ libraries (Eigen, fmt, Catch2) are header-only.

ODR-Use of Template — A template entity that is referenced in a way that requires a definition. Triggers implicit instantiation. The C++ One Definition Rule is relaxed for templates: multiple identical instantiations are allowed across translation units.

Template Argument vs Template ParameterParameter is the placeholder in the declaration (T in template<typename T>). Argument is the actual type or value supplied at the use site (int in vector<int>).

Non-Type Template Parameter — A template parameter that holds a value, not a typetemplate<size_t N> class Array; with Array<5>. The value must be a constant expression known at compile time.

---

PYQ pattern (very common): "What is a function template? Explain with example." — Define generic programming; show template<typename T> syntax; example with max or swap; mention compile-time instantiation.
PYQ pattern: "What is a class template? Write a Stack class as a template." — Define; show Stack<T> with push/pop; instantiate with int and string.
PYQ pattern: "Differentiate function template and function overloading." — Table: overloading has separate code per type; template has one generic; both compile-time; templates reduce duplication.