cpp

Templates

07_Templates⚙️
/**
 * ============================================================
 * C++ FUNCTION TEMPLATES
 * ============================================================
 * 
 * This file covers:
 * - Function template basics
 * - Type deduction
 * - Multiple template parameters
 * - Non-type template parameters
 * - Template specialization
 * - Overloading templates
 * 
 * Compile: g++ -std=c++17 -Wall 01_function_templates.cpp -o func_templates
 * Run: ./func_templates
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <algorithm>
#include <cstring>

using namespace std;

// ============================================================
// PART 1: BASIC FUNCTION TEMPLATE
// ============================================================

// Generic function - works with any type
template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

// Alternative syntax: template <class T> is equivalent
template <class T>
T minimum(T a, T b) {
    return (a < b) ? a : b;
}

// Template with reference parameters
template <typename T>
void swap_values(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

// ============================================================
// PART 2: MULTIPLE TEMPLATE PARAMETERS
// ============================================================

// Two different type parameters
template <typename T1, typename T2>
void printPair(const T1& first, const T2& second) {
    cout << "(" << first << ", " << second << ")" << endl;
}

// Return type as template parameter
template <typename R, typename T1, typename T2>
R add(T1 a, T2 b) {
    return static_cast<R>(a) + static_cast<R>(b);
}

// Auto return type deduction (C++14+)
template <typename T1, typename T2>
auto multiply(T1 a, T2 b) {
    return a * b;
}

// ============================================================
// PART 3: NON-TYPE TEMPLATE PARAMETERS
// ============================================================

// Array with size as template parameter
template <typename T, int SIZE>
class FixedArray {
private:
    T data[SIZE];
    
public:
    T& operator[](int index) {
        return data[index];
    }
    
    const T& operator[](int index) const {
        return data[index];
    }
    
    int size() const { return SIZE; }
    
    void fill(const T& value) {
        for (int i = 0; i < SIZE; i++) {
            data[i] = value;
        }
    }
    
    void print() const {
        cout << "[";
        for (int i = 0; i < SIZE; i++) {
            cout << data[i];
            if (i < SIZE - 1) cout << ", ";
        }
        cout << "]" << endl;
    }
};

// Function with non-type parameter
template <typename T, int N>
T arraySum(const T (&arr)[N]) {
    T sum = T();  // Value initialization
    for (int i = 0; i < N; i++) {
        sum += arr[i];
    }
    return sum;
}

// ============================================================
// PART 4: TEMPLATE SPECIALIZATION
// ============================================================

// Primary template
template <typename T>
void printType(const T& value) {
    cout << "Generic type: " << value << endl;
}

// Full specialization for const char*
template <>
void printType<const char*>(const char* const& value) {
    cout << "C-string: \"" << value << "\" (length: " << strlen(value) << ")" << endl;
}

// Full specialization for bool
template <>
void printType<bool>(const bool& value) {
    cout << "Boolean: " << (value ? "TRUE" : "FALSE") << endl;
}

// Primary template for compare
template <typename T>
int compare(const T& a, const T& b) {
    if (a < b) return -1;
    if (b < a) return 1;
    return 0;
}

// Specialization for C-strings
template <>
int compare<const char*>(const char* const& a, const char* const& b) {
    return strcmp(a, b);
}

// ============================================================
// PART 5: OVERLOADING TEMPLATES
// ============================================================

// Template version
template <typename T>
void process(T value) {
    cout << "Template process: " << value << endl;
}

// Non-template overload (preferred for exact match)
void process(int value) {
    cout << "Int overload process: " << value << endl;
}

// Overload for pointers
template <typename T>
void process(T* ptr) {
    cout << "Pointer process: " << *ptr << endl;
}

// ============================================================
// PART 6: TEMPLATE WITH CONCEPTS (C++20 preview)
// ============================================================

// Without concepts - SFINAE (complex)
template <typename T>
typename enable_if<is_arithmetic<T>::value, T>::type
numericOnly(T value) {
    return value * 2;
}

// C++20 concepts (cleaner syntax)
// template <typename T>
// requires std::integral<T>
// T integerOnly(T value) {
//     return value * 2;
// }

// ============================================================
// PART 7: VARIADIC TEMPLATES
// ============================================================

// Base case for recursion
void printAll() {
    cout << endl;
}

// Variadic template
template <typename T, typename... Args>
void printAll(const T& first, const Args&... rest) {
    cout << first;
    if (sizeof...(rest) > 0) cout << ", ";
    printAll(rest...);  // Recursive call
}

// Fold expression (C++17)
template <typename... Args>
auto sumAll(Args... args) {
    return (args + ...);  // Fold expression
}

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "============================================" << endl;
    cout << "     C++ FUNCTION TEMPLATES" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // DEMO 1: Basic Function Templates
    // ========================================================
    
    cout << "--- DEMO 1: BASIC TEMPLATES ---" << endl << endl;
    
    cout << "maximum(5, 3) = " << maximum(5, 3) << endl;
    cout << "maximum(3.14, 2.72) = " << maximum(3.14, 2.72) << endl;
    cout << "maximum('a', 'z') = " << maximum('a', 'z') << endl;
    cout << "maximum(string(\"apple\"), string(\"banana\")) = " 
         << maximum(string("apple"), string("banana")) << endl;
    
    cout << "\nminimum(10, 20) = " << minimum(10, 20) << endl;
    
    int x = 5, y = 10;
    cout << "\nBefore swap: x=" << x << ", y=" << y << endl;
    swap_values(x, y);
    cout << "After swap:  x=" << x << ", y=" << y << endl;
    
    // Explicit type specification
    cout << "\nExplicit: maximum<double>(5, 3.5) = " << maximum<double>(5, 3.5) << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 2: Multiple Type Parameters
    // ========================================================
    
    cout << "--- DEMO 2: MULTIPLE TYPE PARAMETERS ---" << endl << endl;
    
    printPair(1, "hello");
    printPair(3.14, 42);
    printPair("name", string("value"));
    
    // Return type specified
    cout << "\nadd<double>(5, 3.5) = " << add<double>(5, 3.5) << endl;
    cout << "add<int>(5, 3.5) = " << add<int>(5, 3.5) << endl;
    
    // Auto return type
    cout << "\nmultiply(5, 3.5) = " << multiply(5, 3.5) << endl;
    cout << "multiply(3, 4) = " << multiply(3, 4) << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 3: Non-Type Parameters
    // ========================================================
    
    cout << "--- DEMO 3: NON-TYPE PARAMETERS ---" << endl << endl;
    
    FixedArray<int, 5> arr;
    for (int i = 0; i < arr.size(); i++) {
        arr[i] = i * 10;
    }
    cout << "FixedArray<int, 5>: ";
    arr.print();
    
    FixedArray<double, 3> darr;
    darr.fill(3.14);
    cout << "FixedArray<double, 3>: ";
    darr.print();
    
    int nums[] = {1, 2, 3, 4, 5};
    cout << "\narraySum({1,2,3,4,5}) = " << arraySum(nums) << endl;
    
    double dnums[] = {1.1, 2.2, 3.3};
    cout << "arraySum({1.1,2.2,3.3}) = " << arraySum(dnums) << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 4: Template Specialization
    // ========================================================
    
    cout << "--- DEMO 4: TEMPLATE SPECIALIZATION ---" << endl << endl;
    
    printType(42);           // Uses generic
    printType(3.14);         // Uses generic
    printType("Hello");      // Uses const char* specialization
    printType(true);         // Uses bool specialization
    
    cout << "\nCompare:" << endl;
    cout << "compare(5, 10) = " << compare(5, 10) << endl;
    // ⚠️ LEARNING NOTE: The original code had an error!
    // compare("apple", "banana") fails because:
    // - "apple" is char[6] (5 letters + null terminator)
    // - "banana" is char[7] (6 letters + null terminator)
    // Template deduction sees different types and fails!
    // 
    // FIX: Use std::string or ensure same-length strings
    cout << "compare(string(\"apple\"), string(\"banana\")) = " << compare(string("apple"), string("banana")) << endl;
    cout << "compare(string(\"zebra\"), string(\"apple\")) = " << compare(string("zebra"), string("apple")) << endl;
    
    cout << endl;

    // ========================================================
    // DEMO 5: Template Overloading
    // ========================================================
    
    cout << "--- DEMO 5: TEMPLATE OVERLOADING ---" << endl << endl;
    
    process(42);        // Calls non-template int overload
    process(3.14);      // Calls template
    process("hello");   // Calls template
    
    int val = 100;
    process(&val);      // Calls pointer template
    
    cout << endl;

    // ========================================================
    // DEMO 6: Type Traits / SFINAE
    // ========================================================
    
    cout << "--- DEMO 6: TYPE TRAITS ---" << endl << endl;
    
    cout << "numericOnly(10) = " << numericOnly(10) << endl;
    cout << "numericOnly(3.5) = " << numericOnly(3.5) << endl;
    // numericOnly("hello");  // Would fail to compile - not arithmetic
    
    cout << endl;

    // ========================================================
    // DEMO 7: Variadic Templates
    // ========================================================
    
    cout << "--- DEMO 7: VARIADIC TEMPLATES ---" << endl << endl;
    
    cout << "printAll(1, 2.5, \"three\", 'X'): ";
    printAll(1, 2.5, "three", 'X');
    
    cout << "sumAll(1, 2, 3, 4, 5) = " << sumAll(1, 2, 3, 4, 5) << endl;
    cout << "sumAll(1.1, 2.2, 3.3) = " << sumAll(1.1, 2.2, 3.3) << endl;
    
    cout << endl;

    // ========================================================
    // TEMPLATE SUMMARY
    // ========================================================
    
    cout << "--- FUNCTION TEMPLATE SYNTAX ---" << endl << endl;
    
    cout << "Basic syntax:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "template <typename T>" << endl;
    cout << "T funcName(T param) { ... }" << endl;
    
    cout << "\nMultiple parameters:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "template <typename T1, typename T2>" << endl;
    cout << "auto func(T1 a, T2 b) { ... }" << endl;
    
    cout << "\nNon-type parameters:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "template <typename T, int SIZE>" << endl;
    cout << "void func(T (&arr)[SIZE]) { ... }" << endl;
    
    cout << "\nSpecialization:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "template <>" << endl;
    cout << "void func<SpecificType>(...) { ... }" << endl;
    
    cout << "\nVariadic:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "template <typename... Args>" << endl;
    cout << "void func(Args... args) { ... }" << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "FUNCTION TEMPLATES COMPLETE!" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Create a template function findInArray that:
 *    - Takes an array and value to find
 *    - Returns index or -1 if not found
 *    - Specialize for C-strings using strcmp
 * 
 * 2. Create a template function printContainer that:
 *    - Works with any container (vector, array, list)
 *    - Uses iterators
 *    - Prints elements separated by commas
 * 
 * 3. Create variadic template functions:
 *    - maxAll() - returns maximum of all arguments
 *    - makeString() - concatenates all arguments
 * 
 * 4. Create template with type traits:
 *    - average() that only works with numeric types
 *    - Uses static_assert or SFINAE
 */
Templates - C++ Tutorial | DeepML