#include <iostream>
#include <string>
#include <utility>   // std::forward
#include <cstring>   // strcmp

// ==================== 1. Basic function template ====================
template <typename T>
T maxValue(T a, T b) {
    return (a > b) ? a : b;
}

// ==================== 2. Explicit template arguments + decltype return type ====================
template <typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
    return a + b;
}

// ==================== 3. Function template overloads (coexisting with regular functions) ====================
void printInfo(int x) {
    std::cout << "Regular function: int = " << x << std::endl;
}

template <typename T>
void printInfo(T x) {
    std::cout << "Template function: T = " << x << std::endl;
}

template <typename T>
void printInfo(T x, T y) {
    std::cout << "Template overload: (" << x << ", " << y << ")" << std::endl;
}

// ==================== 4. Template specialization (full specialization) ====================
template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return strcmp(a, b) == 0;
}

// ==================== 5. Non-type template parameters ====================
template <typename T, int Size>
T sumArray(T (&arr)[Size]) {
    T sum = 0;
    for (int i = 0; i < Size; ++i)
        sum += arr[i];
    return sum;
}

// ==================== 6. Default template parameters ====================
template <typename T, typename Comparator = std::greater<T>>
bool compare(T a, T b, Comparator comp = Comparator()) {
    return comp(a, b);
}

// ==================== 7. auto return type (C++14) ====================
template <typename T, typename U>
auto multiply(T a, U b) {
    return a * b;
}

// ==================== 8. Perfect forwarding (requires static_cast for overloaded functions) ====================
// Target functions: overloads
void targetFunc(int& x) {
    std::cout << "targetFunc: lvalue reference, value = " << x << std::endl;
}
void targetFunc(int&& x) {
    std::cout << "targetFunc: rvalue reference, value = " << x << std::endl;
}

// Perfect forwarding wrapper
template <typename F, typename... Args>
void forwardCall(F&& f, Args&&... args) {
    std::forward<F>(f)(std::forward<Args>(args)...);
}

// ==================== 9. Variadic templates ====================
void printAll() {
    std::cout << std::endl;
}

template <typename T, typename... Args>
void printAll(T first, Args... rest) {
    std::cout << first << " ";
    printAll(rest...);
}

// ==================== Main function ====================
int main() {
    std::cout << "========== 1. Basic function template ==========" << std::endl;
    std::cout << "maxValue(10, 20) = " << maxValue(10, 20) << std::endl;
    std::cout << "maxValue(3.14, 2.71) = " << maxValue(3.14, 2.71) << std::endl;

    std::cout << "\n========== 2. Explicit template arguments ==========" << std::endl;
    auto result = add<int, double>(5, 3.2);
    std::cout << "add<int, double>(5, 3.2) = " << result << std::endl;

    std::cout << "\n========== 3. Function template overloads ==========" << std::endl;
    printInfo(100);      // regular function preferred
    printInfo(3.14);     // calls template
    printInfo(5, 6);     // calls template overload

    std::cout << "\n========== 4. Template specialization ==========" << std::endl;
    std::cout << std::boolalpha;
    std::cout << "isEqual(10, 10) = " << isEqual(10, 10) << std::endl;
    std::cout << "isEqual(5, 3)   = " << isEqual(5, 3) << std::endl;
    const char* str1 = "hello";
    const char* str2 = "hello";
    const char* str3 = "world";
    std::cout << "isEqual(\"hello\", \"hello\") = " << isEqual(str1, str2) << std::endl;
    std::cout << "isEqual(\"hello\", \"world\") = " << isEqual(str1, str3) << std::endl;

    std::cout << "\n========== 5. Non-type template parameters (array size) ==========" << std::endl;
    int arr[] = {1, 2, 3, 4, 5};
    double darr[] = {1.1, 2.2, 3.3};
    std::cout << "sumArray(arr)  = " << sumArray(arr) << std::endl;
    std::cout << "sumArray(darr) = " << sumArray(darr) << std::endl;

    std::cout << "\n========== 6. Default template parameters (comparator) ==========" << std::endl;
    std::cout << "compare(10, 20) default greater: " << compare(10, 20) << std::endl;
    std::cout << "compare(10, 20, std::less<int>()) : " << compare(10, 20, std::less<int>()) << std::endl;

    std::cout << "\n========== 7. auto return type ==========" << std::endl;
    auto mul = multiply(3, 4.5);
    std::cout << "multiply(3, 4.5) = " << mul << " , type: " << typeid(mul).name() << std::endl;

    std::cout << "\n========== 8. Perfect forwarding (overloaded functions) ==========" << std::endl;
    int lv = 42;
    // Use static_cast to explicitly select the overload to forward
    forwardCall(static_cast<void(*)(int&)>(targetFunc), lv);   // lvalue version
    forwardCall(static_cast<void(*)(int&&)>(targetFunc), 100); // rvalue version

    std::cout << "\n========== 9. Variadic templates ==========" << std::endl;
    printAll("Parameter pack:", 1, 2.5, 'c', "hello", 100);
    printAll("Empty parameter pack:");

    return 0;
}

results matching ""

    No results matching ""