Chapter 18 Advanced 52 Questions

Practice Questions — Templates - Function and Class Templates

← Back to Notes
10 Easy
9 Medium
9 Hard

Topic-Specific Questions

Question 1
Easy
What is the output of the following code?
#include <iostream>
using namespace std;
template<typename T>
T add(T a, T b) {
    return a + b;
}
int main() {
    cout << add(3, 4) << endl;
    cout << add(2.5, 3.5) << endl;
    return 0;
}
T is deduced from arguments: int for (3,4), double for (2.5,3.5).
7
6
Question 2
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T>
class Wrapper {
    T val;
public:
    Wrapper(T v) : val(v) {}
    T get() const { return val; }
};
int main() {
    Wrapper<int> w1(42);
    Wrapper<string> w2("Arjun");
    cout << w1.get() << endl;
    cout << w2.get() << endl;
    return 0;
}
Wrapper stores an int. Wrapper stores a string.
42
Arjun
Question 3
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T>
T maxOf(T a, T b) {
    return (a > b) ? a : b;
}
int main() {
    cout << maxOf(10, 20) << endl;
    cout << maxOf('A', 'Z') << endl;
    return 0;
}
maxOf works with any type that supports >. Chars are compared by ASCII values.
20
Z
Question 4
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T, int N>
class Array {
    T data[N];
public:
    void fill(T val) {
        for (int i = 0; i < N; i++) data[i] = val;
    }
    void print() const {
        for (int i = 0; i < N; i++) cout << data[i] << " ";
        cout << endl;
    }
    int size() const { return N; }
};
int main() {
    Array<int, 4> arr;
    arr.fill(7);
    arr.print();
    cout << "Size: " << arr.size() << endl;
    return 0;
}
N=4 is a non-type template parameter. The array has exactly 4 elements filled with 7.
7 7 7 7
Size: 4
Question 5
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T>
void display(T val) {
    cout << "Generic: " << val << endl;
}
template<>
void display<bool>(bool val) {
    cout << "Bool: " << (val ? "true" : "false") << endl;
}
int main() {
    display(42);
    display(3.14);
    display(true);
    return 0;
}
display is fully specialized. Other types use the generic version.
Generic: 42
Generic: 3.14
Bool: true
Question 6
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
    return a * b;
}
int main() {
    cout << multiply(3, 4) << endl;
    cout << multiply(3, 4.5) << endl;
    cout << multiply(2.5, 4) << endl;
    return 0;
}
The return type is deduced from a*b. int*int=int, int*double=double.
12
13.5
10
Question 7
Medium
What is the output?
#include <iostream>
using namespace std;
void print() { cout << endl; }
template<typename T, typename... Args>
void print(T first, Args... rest) {
    cout << first << " ";
    print(rest...);
}
int main() {
    print(1, 2, 3);
    print("Kavya", 25, 'A');
    return 0;
}
Variadic template peels off the first argument and recurses. Base case prints newline.
1 2 3
Kavya 25 A
Question 8
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T>
class Pair {
    T first, second;
public:
    Pair(T a, T b) : first(a), second(b) {}
    T getFirst() const { return first; }
    T getSecond() const { return second; }
    T sum() const { return first + second; }
};
int main() {
    Pair<int> p1(10, 20);
    Pair<double> p2(1.5, 2.5);
    cout << p1.sum() << endl;
    cout << p2.sum() << endl;
    Pair<string> p3("Hello, ", "World");
    cout << p3.sum() << endl;
    return 0;
}
sum() uses operator+ which works for int, double, and string (concatenation).
30
4
Hello, World
Question 9
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T>
class Info {
public:
    static string type() { return "unknown"; }
};
template<> class Info<int> {
public:
    static string type() { return "int"; }
};
template<> class Info<double> {
public:
    static string type() { return "double"; }
};
template<typename T>
class Info<T*> {
public:
    static string type() { return "pointer to " + Info<T>::type(); }
};
int main() {
    cout << Info<int>::type() << endl;
    cout << Info<float>::type() << endl;
    cout << Info<int*>::type() << endl;
    cout << Info<double*>::type() << endl;
    cout << Info<int**>::type() << endl;
    return 0;
}
int* matches partial specialization T*. int** matches T* where T=int*, which recursively uses T* again.
int
unknown
pointer to int
pointer to double
pointer to pointer to int
Question 10
Hard
What is the output?
#include <iostream>
using namespace std;
template<int N>
struct Factorial {
    static const int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
    static const int value = 1;
};
int main() {
    cout << Factorial<5>::value << endl;
    cout << Factorial<0>::value << endl;
    cout << Factorial<8>::value << endl;
    return 0;
}
Compile-time recursion. Factorial<5> = 5 * Factorial<4> = 5*4*3*2*1*1 = 120.
120
1
40320
Question 11
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T, typename U>
class Pair {
public:
    void info() { cout << "Generic" << endl; }
};
template<typename T>
class Pair<T, T> {
public:
    void info() { cout << "Same types" << endl; }
};
template<typename T>
class Pair<T, int> {
public:
    void info() { cout << "Second is int" << endl; }
};
int main() {
    Pair<double, string> p1; p1.info();
    Pair<double, double> p2; p2.info();
    Pair<string, int> p3; p3.info();
    Pair<int, int> p4; p4.info();
    return 0;
}
Pair could match both and . Which is more specialized?
Generic
Same types
Second is int
Same types
Question 12
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T>
T sum(T val) { return val; }
template<typename T, typename... Args>
T sum(T first, Args... rest) {
    return first + sum(rest...);
}
int main() {
    cout << sum(1, 2, 3, 4, 5) << endl;
    cout << sum(10) << endl;
    return 0;
}
sum(1,2,3,4,5) = 1 + sum(2,3,4,5) = 1+2+sum(3,4,5) = ... = 15. sum(10) hits base case directly.
15
10
Question 13
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T>
T square(T x) { return x * x; }
int main() {
    cout << square(5) << endl;
    cout << square(2.5) << endl;
    return 0;
}
square(5) deduces T=int. square(2.5) deduces T=double.
25
6.25
Question 14
Easy
What is the output?
#include <iostream>
#include <string>
using namespace std;
template<typename T>
bool isEqual(T a, T b) { return a == b; }
int main() {
    cout << isEqual(10, 10) << endl;
    cout << isEqual(string("Ravi"), string("Ravi")) << endl;
    cout << isEqual(3.14, 3.15) << endl;
    return 0;
}
isEqual compares using ==. Works for int, string, and double.
1
1
0
Question 15
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T, int N>
T arraySum(T (&arr)[N]) {
    T total = T();
    for (int i = 0; i < N; i++) total += arr[i];
    return total;
}
int main() {
    int a[] = {10, 20, 30};
    double b[] = {1.5, 2.5};
    cout << arraySum(a) << endl;
    cout << arraySum(b) << endl;
    return 0;
}
Both T and N are deduced from the array reference. T() initializes to 0 for numeric types.
60
4
Question 16
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T>
class MinMax {
    T minVal, maxVal;
public:
    MinMax(T a, T b) {
        minVal = (a < b) ? a : b;
        maxVal = (a > b) ? a : b;
    }
    T getMin() const { return minVal; }
    T getMax() const { return maxVal; }
};
int main() {
    MinMax<int> m(30, 10);
    cout << m.getMin() << " " << m.getMax() << endl;
    MinMax<string> s("Arjun", "Priya");
    cout << s.getMin() << " " << s.getMax() << endl;
    return 0;
}
MinMax sorts two values. Strings are compared lexicographically.
10 30
Arjun Priya
Question 17
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T>
void show(T val) { cout << "value: " << val << endl; }
template<typename T>
void show(T* ptr) { cout << "pointer: " << *ptr << endl; }
template<>
void show<int>(int val) { cout << "int: " << val << endl; }
int main() {
    int x = 42;
    show(x);
    show(&x);
    show(3.14);
    show(&x + 0);
    return 0;
}
show(x) matches the int specialization. show(&x) matches the pointer overload. show(3.14) matches generic.
int: 42
pointer: 42
value: 3.14
pointer: 42
Question 18
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T, typename U = T>
class Container {
    T first;
    U second;
public:
    Container(T a, U b) : first(a), second(b) {}
    void show() { cout << first << " " << second << endl; }
};
int main() {
    Container<int> c1(10, 20);
    Container<int, double> c2(10, 3.14);
    c1.show();
    c2.show();
    return 0;
}
Container uses default U=int. Container specifies U=double.
10 20
10 3.14

Mixed & Application Questions

Question 1
Easy
What is the difference between a function template and a template function?
One is the blueprint, the other is the generated code.
A function template is the blueprint (template T add(T a, T b)). A template function is a specific instantiation generated by the compiler (e.g., add is a template function). The template is the code you write; the template function is the code the compiler generates.
Question 2
Easy
Why must template definitions be placed in header files?
Think about what the compiler needs to see at the point of instantiation.
The compiler needs to see the full template definition to generate code for a specific type. If the definition is in a .cpp file, other translation units cannot see it and the linker reports undefined references.
Question 3
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T>
void print(T val) {
    cout << val << endl;
}
int main() {
    print(42);
    print(3.14);
    print("Ravi");
    return 0;
}
The template deduces T from each argument.
42
3.14
Ravi
Question 4
Easy
What is the output?
#include <iostream>
using namespace std;
template<typename T = int>
class Container {
    T val;
public:
    Container(T v) : val(v) {}
    T get() const { return val; }
};
int main() {
    Container<> c1(100);
    Container<double> c2(3.14);
    cout << c1.get() << endl;
    cout << c2.get() << endl;
    return 0;
}
Container<> uses the default type int. Container overrides the default.
100
3.14
Question 5
Medium
What happens when you compile this code?
#include <iostream>
using namespace std;
template<typename T>
T add(T a, T b) { return a + b; }
int main() {
    cout << add(3, 4.5) << endl;
    return 0;
}
T is deduced from both arguments. 3 deduces int, 4.5 deduces double. Do they match?
Compilation error: deduced conflicting types for parameter T (int vs double).
Question 6
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T, int N>
T sumArray(T (&arr)[N]) {
    T total = T();
    for (int i = 0; i < N; i++) total += arr[i];
    return total;
}
int main() {
    int a[] = {1, 2, 3, 4, 5};
    double b[] = {1.5, 2.5, 3.5};
    cout << sumArray(a) << endl;
    cout << sumArray(b) << endl;
    return 0;
}
The template deduces both T and N from the array reference. N is the array size.
15
7.5
Question 7
Medium
What is the output?
#include <iostream>
using namespace std;
template<typename T>
class Box {
    T val;
public:
    Box(T v) : val(v) {}
    bool operator>(const Box& other) const { return val > other.val; }
    T get() const { return val; }
};
template<typename T>
Box<T> maxBox(Box<T> a, Box<T> b) {
    return (a > b) ? a : b;
}
int main() {
    Box<int> a(10), b(20);
    cout << maxBox(a, b).get() << endl;
    Box<string> s1("Arjun"), s2("Priya");
    cout << maxBox(s1, s2).get() << endl;
    return 0;
}
maxBox uses the > operator which Box overloads. For strings, > uses lexicographic comparison.
20
Priya
Question 8
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename T>
void process(T val) {
    cout << "Value: " << val << endl;
}
template<typename T>
void process(T* ptr) {
    cout << "Pointer to: " << *ptr << endl;
}
template<>
void process<int>(int val) {
    cout << "Int: " << val << endl;
}
int main() {
    int x = 42;
    process(x);
    process(&x);
    process(3.14);
    return 0;
}
Overload resolution: process(x) matches both generic T and specialization int. Specialization wins for exact match. process(&x) matches the pointer overload.
Int: 42
Pointer to: 42
Value: 3.14
Question 9
Hard
What is the output?
#include <iostream>
using namespace std;
template<int N>
struct Fib {
    static const int value = Fib<N-1>::value + Fib<N-2>::value;
};
template<> struct Fib<0> { static const int value = 0; };
template<> struct Fib<1> { static const int value = 1; };
int main() {
    cout << Fib<0>::value << endl;
    cout << Fib<1>::value << endl;
    cout << Fib<6>::value << endl;
    cout << Fib<10>::value << endl;
    return 0;
}
Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55. Index 6 = 8, index 10 = 55.
0
1
8
55
Question 10
Hard
What is the output?
#include <iostream>
using namespace std;
template<typename... Args>
int countArgs(Args... args) {
    return sizeof...(args);
}
int main() {
    cout << countArgs() << endl;
    cout << countArgs(1) << endl;
    cout << countArgs(1, 2.5, "three", 'A') << endl;
    return 0;
}
sizeof...(args) returns the number of arguments in the parameter pack at compile time.
0
1
4

Multiple Choice Questions

MCQ 1
What is the keyword used to define a template in C++?
  • A. generic
  • B. template
  • C. typename
  • D. class
Answer: B
B is correct. The template keyword is used before the function or class to define a template. typename and class are used inside the template parameter list.
MCQ 2
What is the difference between template and template?
  • A. typename works with built-in types, class with user-defined types
  • B. They are identical in template parameter declarations
  • C. class allows default arguments, typename does not
  • D. typename is for function templates, class for class templates
Answer: B
B is correct. In template parameter declarations, typename and class are interchangeable. Both accept any type (built-in or user-defined). The convention is to use typename in modern C++.
MCQ 3
When does the compiler generate code from a template?
  • A. At runtime
  • B. When the template is defined
  • C. When the template is instantiated (used with specific types)
  • D. During linking
Answer: C
C is correct. Templates are instantiated at compile time when they are used with specific type arguments. The compiler generates a separate version of the function/class for each unique set of template arguments.
MCQ 4
What is a non-type template parameter?
  • A. A parameter with no type
  • B. A compile-time constant value (like int) used as a template argument
  • C. A parameter that accepts only void
  • D. A parameter that is ignored by the compiler
Answer: B
B is correct. Non-type template parameters accept compile-time constant values, such as integers, pointers, or enums. Example: template<int N> where N must be a compile-time constant.
MCQ 5
Which C++ library is entirely built on templates?
  • A. stdio.h
  • B. math.h
  • C. The Standard Template Library (STL)
  • D. pthread.h
Answer: C
C is correct. The STL (containers like vector, map; algorithms like sort, find; utilities like pair, tuple) is entirely implemented using templates.
MCQ 6
Which of the following supports partial specialization?
  • A. Function templates only
  • B. Class templates only
  • C. Both function and class templates
  • D. Neither
Answer: B
B is correct. Only class templates support partial specialization. Function templates must use overloading as an alternative to partial specialization.
MCQ 7
What does sizeof...(Args) return in a variadic template?
  • A. The total memory size of all arguments
  • B. The number of arguments in the parameter pack
  • C. The size of the largest argument
  • D. Zero always
Answer: B
B is correct. sizeof...(Args) is a compile-time operator that returns the number of elements in a template parameter pack or function parameter pack.
MCQ 8
What is the purpose of decltype in C++?
  • A. To declare a new type
  • B. To get the type of an expression at compile time without evaluating it
  • C. To convert types at runtime
  • D. To delete a type definition
Answer: B
B is correct. decltype(expr) yields the type of the expression expr at compile time. It does not evaluate the expression. It is commonly used in trailing return types.
MCQ 9
What happens when you put template definitions in a .cpp file?
  • A. The code compiles and links normally
  • B. Compilation succeeds but linking fails with undefined reference errors
  • C. The code runs slower
  • D. The template is ignored
Answer: B
B is correct. The .cpp file compiles fine, but other translation units cannot see the template definition and cannot instantiate it. The linker cannot find the generated code, resulting in undefined reference errors.
MCQ 10
What is SFINAE in C++ templates?
  • A. A compiler optimization technique
  • B. Substitution Failure Is Not An Error: if template argument substitution fails, the template is silently discarded
  • C. A runtime error handling mechanism
  • D. A memory allocation strategy
Answer: B
B is correct. SFINAE means that when the compiler tries to instantiate a template and substitution of template arguments makes the declaration ill-formed, the template is silently removed from the overload set instead of causing a compilation error.
MCQ 11
What is the output of Pair p; p.info(); given partial specializations and ?
  • A. Ambiguous, compilation error
  • B. Generic Pair
  • C. Same-type Pair (the <T,T> specialization wins)
  • D. Pair with int second
Answer: C
C is correct. When Pair<int, int> matches both <T,T> and <T,int>, the compiler uses partial ordering rules. <T,T> is more specialized because it constrains both parameters, so it wins.
MCQ 12
In a variadic template, what does the ... (ellipsis) do in print(rest...)?
  • A. Converts rest to a C-style variadic argument
  • B. Expands the parameter pack, passing each element as a separate argument
  • C. Concatenates all arguments into one
  • D. Discards all remaining arguments
Answer: B
B is correct. The ... after a parameter pack name is the pack expansion operator. rest... expands to arg1, arg2, arg3, ..., passing each element as a separate argument to the recursive call.
MCQ 13
What is the advantage of templates over void* for generic programming?
  • A. Templates are faster at runtime
  • B. Templates provide full type safety at compile time while void* loses all type information
  • C. Templates use less memory
  • D. void* cannot store integers
Answer: B
B is correct. Templates preserve complete type information and enable compile-time type checking. void* erases type information, requiring manual casts that can cause runtime errors if incorrect.
MCQ 14
Can a template have both type and non-type parameters?
  • A. No, a template must have only one kind of parameter
  • B. Yes, for example template<typename T, int N>
  • C. Only class templates can mix them
  • D. Only with C++17 or later
Answer: B
B is correct. Templates can freely mix type parameters (typename T) and non-type parameters (int N). Example: template<typename T, int N> class Array.
MCQ 15
What is the difference between full specialization and partial specialization?
  • A. Full specialization provides implementation for all types; partial for some
  • B. Full specialization fixes all template parameters; partial fixes some while leaving others generic
  • C. They are the same thing
  • D. Full is for classes; partial is for functions
Answer: B
B is correct. Full specialization (template<>) provides a specific implementation for a complete set of template arguments. Partial specialization fixes some parameters while leaving others generic.
MCQ 16
What does template argument deduction mean?
  • A. The programmer must always specify template arguments
  • B. The compiler automatically determines template arguments from function call arguments
  • C. The template arguments are deduced at runtime
  • D. Only class templates support deduction
Answer: B
B is correct. When calling a function template, the compiler can deduce the template arguments from the types of the function arguments. For example, maxOf(3, 4) deduces T=int.
MCQ 17
What is template metaprogramming?
  • A. Writing templates that generate code at runtime
  • B. Using templates to perform computations at compile time through recursive instantiation
  • C. A way to avoid using templates
  • D. Using macros instead of templates
Answer: B
B is correct. Template metaprogramming uses recursive template instantiation and specialization to perform computations at compile time. Examples include compile-time factorial, Fibonacci, and type traits.
MCQ 18
Why can function templates not be partially specialized?
  • A. It is a compiler limitation that will be fixed in future standards
  • B. The C++ standard prohibits it; function overloading serves the same purpose
  • C. Function templates do not support any specialization
  • D. They can be partially specialized in C++20
Answer: B
B is correct. The C++ standard does not allow partial specialization of function templates. Instead, function overloading achieves the same effect. Overload resolution is more intuitive for functions than partial specialization would be.
MCQ 19
What is CTAD (Class Template Argument Deduction) introduced in C++17?
  • A. A way to prevent template argument deduction
  • B. Allows the compiler to deduce class template arguments from constructor arguments without explicit specification
  • C. A new way to specialize templates
  • D. A debugging tool for templates
Answer: B
B is correct. Prior to C++17, you had to write pair<int, double> p(1, 2.5);. With CTAD, you can write pair p(1, 2.5); and the compiler deduces the template arguments from the constructor arguments.

Coding Challenges

Challenge 1: Generic Pair Class with Comparison

Easy
Create a class template Pair that stores two values of possibly different types. Provide getFirst(), getSecond(), and overload operator== to compare two pairs. Demonstrate with int/string and double/double pairs.
Sample Input
Pair<int, string>(1, "Arjun") and Pair<int, string>(1, "Arjun"); Pair<double, double>(3.14, 2.71)
Sample Output
(1, Arjun) (1, Arjun) Equal: 1 (3.14, 2.71)
Use two template parameters. Overload == and <<.
#include <iostream>
#include <string>
using namespace std;

template<typename T, typename U>
class Pair {
    T first;
    U second;
public:
    Pair(T f, U s) : first(f), second(s) {}
    T getFirst() const { return first; }
    U getSecond() const { return second; }
    bool operator==(const Pair& other) const {
        return first == other.first && second == other.second;
    }
    friend ostream& operator<<(ostream& os, const Pair& p) {
        os << "(" << p.first << ", " << p.second << ")";
        return os;
    }
};

int main() {
    Pair<int, string> p1(1, "Arjun"), p2(1, "Arjun");
    cout << p1 << endl;
    cout << p2 << endl;
    cout << "Equal: " << (p1 == p2) << endl;

    Pair<double, double> p3(3.14, 2.71);
    cout << p3 << endl;
    return 0;
}

Challenge 2: Generic Sorting with Function Templates

Medium
Write a function template bubbleSort that sorts an array of any type T in ascending order. Write a function template printArray that prints the array. Demonstrate with int, double, and string arrays.
Sample Input
int: {5, 2, 8, 1, 9}, double: {3.14, 1.41, 2.71}, string: {"Ravi", "Arjun", "Kavya"}
Sample Output
int: 1 2 5 8 9 double: 1.41 2.71 3.14 string: Arjun Kavya Ravi
Use template<typename T> for both functions. Use reference to array or pointer+size.
#include <iostream>
#include <string>
using namespace std;

template<typename T>
void bubbleSort(T arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                T temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

template<typename T>
void printArray(T arr[], int n) {
    for (int i = 0; i < n; i++) {
        cout << arr[i];
        if (i < n - 1) cout << " ";
    }
    cout << endl;
}

int main() {
    int ints[] = {5, 2, 8, 1, 9};
    bubbleSort(ints, 5);
    cout << "int: "; printArray(ints, 5);

    double doubles[] = {3.14, 1.41, 2.71};
    bubbleSort(doubles, 3);
    cout << "double: "; printArray(doubles, 3);

    string strings[] = {"Ravi", "Arjun", "Kavya"};
    bubbleSort(strings, 3);
    cout << "string: "; printArray(strings, 3);
    return 0;
}

Challenge 3: Type-Safe Generic Stack with Specialization

Medium
Create a class template Stack with push, pop, peek, size, and empty. Create a full specialization Stack that stores bools efficiently by printing a special message on push/pop. Demonstrate both the generic and specialized versions.
Sample Input
Stack<int>: push 10, 20, 30. Pop. Stack<bool>: push true, false. Pop.
Sample Output
Pushed int: 30 Peek: 30 Popped: 30 Size: 2 Pushed bool: true Pushed bool: false Popped bool: false
Full specialization for bool. Show different behavior for bool vs generic.
#include <iostream>
using namespace std;

template<typename T>
class Stack {
    T data[100];
    int top;
public:
    Stack() : top(-1) {}
    void push(T val) {
        data[++top] = val;
        cout << "Pushed int: " << val << endl;
    }
    T pop() {
        T val = data[top--];
        cout << "Popped: " << val << endl;
        return val;
    }
    T peek() const { return data[top]; }
    int size() const { return top + 1; }
    bool empty() const { return top == -1; }
};

template<>
class Stack<bool> {
    bool data[100];
    int top;
public:
    Stack() : top(-1) {}
    void push(bool val) {
        data[++top] = val;
        cout << "Pushed bool: " << (val ? "true" : "false") << endl;
    }
    bool pop() {
        bool val = data[top--];
        cout << "Popped bool: " << (val ? "true" : "false") << endl;
        return val;
    }
    bool peek() const { return data[top]; }
    int size() const { return top + 1; }
    bool empty() const { return top == -1; }
};

int main() {
    Stack<int> intStack;
    intStack.push(10);
    intStack.push(20);
    intStack.push(30);
    cout << "Peek: " << intStack.peek() << endl;
    intStack.pop();
    cout << "Size: " << intStack.size() << endl;

    Stack<bool> boolStack;
    boolStack.push(true);
    boolStack.push(false);
    boolStack.pop();
    return 0;
}

Challenge 4: Compile-Time Power Calculation

Hard
Create a template metaprogram Power that computes Base^Exp at compile time. Specialize for Exp=0 (result is 1). Also create a variadic template function printAll that prints any number of arguments. Demonstrate both.
Sample Input
Power<2,10>, Power<3,4>, Power<5,0>. printAll(1, 2.5, "Priya", true).
Sample Output
2^10 = 1024 3^4 = 81 5^0 = 1 1 2.5 Priya 1
Use template recursion for Power. Use variadic templates for printAll. All Power values computed at compile time.
#include <iostream>
using namespace std;

template<int Base, int Exp>
struct Power {
    static const long long value = Base * Power<Base, Exp - 1>::value;
};

template<int Base>
struct Power<Base, 0> {
    static const long long value = 1;
};

void printAll() { cout << endl; }

template<typename T, typename... Args>
void printAll(T first, Args... rest) {
    cout << first;
    if (sizeof...(rest) > 0) cout << " ";
    printAll(rest...);
}

int main() {
    cout << "2^10 = " << Power<2, 10>::value << endl;
    cout << "3^4 = " << Power<3, 4>::value << endl;
    cout << "5^0 = " << Power<5, 0>::value << endl;
    printAll(1, 2.5, "Priya", true);
    return 0;
}

Challenge 5: Generic Matrix with Non-Type Parameters

Hard
Create a class template Matrix using non-type template parameters for dimensions. Implement set(), get(), operator+ (for same-dimension matrices), and a print method. Demonstrate with 2x3 int matrices and 2x2 double matrices.
Sample Input
Matrix A(2x3): {1,2,3,4,5,6}. Matrix B(2x3): {6,5,4,3,2,1}. C = A + B.
Sample Output
A: 1 2 3 4 5 6 B: 6 5 4 3 2 1 A+B: 7 7 7 7 7 7
Use non-type template parameters for Rows and Cols. Size known at compile time. operator+ only compiles for matching dimensions.
#include <iostream>
using namespace std;

template<typename T, int Rows, int Cols>
class Matrix {
    T data[Rows][Cols];
public:
    Matrix() {
        for (int i = 0; i < Rows; i++)
            for (int j = 0; j < Cols; j++)
                data[i][j] = T();
    }

    void set(int r, int c, T val) { data[r][c] = val; }
    T get(int r, int c) const { return data[r][c]; }

    Matrix operator+(const Matrix& other) const {
        Matrix result;
        for (int i = 0; i < Rows; i++)
            for (int j = 0; j < Cols; j++)
                result.data[i][j] = data[i][j] + other.data[i][j];
        return result;
    }

    void print() const {
        for (int i = 0; i < Rows; i++) {
            for (int j = 0; j < Cols; j++) {
                cout << data[i][j];
                if (j < Cols - 1) cout << " ";
            }
            cout << endl;
        }
    }
};

int main() {
    Matrix<int, 2, 3> A, B;
    int val = 1;
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 3; j++) {
            A.set(i, j, val);
            B.set(i, j, 7 - val);
            val++;
        }

    cout << "A:" << endl; A.print();
    cout << "B:" << endl; B.print();
    Matrix<int, 2, 3> C = A + B;
    cout << "A+B:" << endl; C.print();
    return 0;
}

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn C++ with a live mentor?

Explore our C++ Masterclass