cpp

exercises

exercises.cpp⚙️
/**
 * Advanced Templates - Exercises
 * Compile: g++ -std=c++17 -Wall exercises.cpp -o exercises
 */

#include <iostream>
#include <string>
#include <type_traits>
using namespace std;

// ============================================================
// Exercise 1: Variadic Print ⭐⭐
// ============================================================

// TODO: Create printLine(args...) that prints all arguments
// separated by " | " and ending with newline

void exercise1() {
    // printLine(1, 2.5, "hello");
    // Output: 1 | 2.5 | hello
    cout << "(Implement variadic printLine)" << endl;
}

// ============================================================
// Exercise 2: Fold Sum/Product ⭐⭐
// ============================================================

// TODO: Create using fold expressions:
// - sumAll(args...) - returns sum
// - productAll(args...) - returns product
// - minAll(args...) - returns minimum

void exercise2() {
    // cout << sumAll(1,2,3,4,5) << endl;      // 15
    // cout << productAll(1,2,3,4) << endl;    // 24
    // cout << minAll(5,2,8,1,9) << endl;      // 1
    cout << "(Implement fold expressions)" << endl;
}

// ============================================================
// Exercise 3: Type Checker ⭐⭐
// ============================================================

// TODO: Create getTypeInfo<T>() that returns string:
// "integral" for int, long, etc.
// "floating" for float, double
// "pointer" for pointer types
// "other" for everything else
// Use if constexpr

void exercise3() {
    // cout << getTypeInfo<int>() << endl;      // "integral"
    // cout << getTypeInfo<double>() << endl;   // "floating"
    // cout << getTypeInfo<int*>() << endl;     // "pointer"
    cout << "(Implement type info with if constexpr)" << endl;
}

// ============================================================
// Exercise 4: Safe Divide ⭐⭐⭐
// ============================================================

// TODO: Create safeDivide(a, b) that:
// - Works with arithmetic types only (use SFINAE or if constexpr)
// - Returns a/b for integers (integer division)
// - Returns a/b for floating point
// - Returns 0 if b is 0

void exercise4() {
    // cout << safeDivide(10, 3) << endl;    // 3
    // cout << safeDivide(10.0, 3.0) << endl; // 3.333...
    // cout << safeDivide(5, 0) << endl;      // 0
    cout << "(Implement SFINAE safeDivide)" << endl;
}

// ============================================================
// Exercise 5: Compile-Time Power ⭐⭐⭐
// ============================================================

// TODO: Create template struct Power<Base, Exp>
// with static constexpr value member
// Power<2, 10>::value should be 1024

void exercise5() {
    // cout << Power<2, 10>::value << endl;  // 1024
    // cout << Power<3, 4>::value << endl;   // 81
    cout << "(Implement compile-time Power)" << endl;
}

// ============================================================
// Exercise 6: Count Types ⭐⭐⭐
// ============================================================

// TODO: Create CountType<T, Types...> that counts
// how many times T appears in Types...
// CountType<int, int, double, int, char>::value = 2

void exercise6() {
    // cout << CountType<int, int, double, int, char>::value << endl; // 2
    // cout << CountType<char, int, double>::value << endl;           // 0
    cout << "(Implement CountType)" << endl;
}

// ============================================================
// Exercise 7: Invoke All ⭐⭐⭐
// ============================================================

// TODO: Create invokeAll(funcs..., arg) that calls
// each function with the same argument

void exercise7() {
    // auto f1 = [](int x) { cout << x * 2 << " "; };
    // auto f2 = [](int x) { cout << x + 1 << " "; };
    // invokeAll(5, f1, f2);  // prints: 10 6
    cout << "(Implement invokeAll with variadic)" << endl;
}

// ============================================================
// Exercise 8: Make Array ⭐⭐⭐
// ============================================================

// TODO: Create makeArray(args...) that returns
// array<CommonType, sizeof...(args)>
// All args must be same or convertible type

void exercise8() {
    // auto arr = makeArray(1, 2, 3, 4, 5);
    // for (auto x : arr) cout << x << " ";
    cout << "(Implement makeArray)" << endl;
}

// ============================================================
// MAIN
// ============================================================

int main() {
    cout << "=== Advanced Templates Exercises ===" << endl;
    
    cout << "\nEx1: Variadic Print" << endl;
    exercise1();
    
    cout << "\nEx2: Fold Operations" << endl;
    exercise2();
    
    cout << "\nEx3: Type Checker" << endl;
    exercise3();
    
    cout << "\nEx4: Safe Divide" << endl;
    exercise4();
    
    cout << "\nEx5: Compile-Time Power" << endl;
    exercise5();
    
    cout << "\nEx6: Count Types" << endl;
    exercise6();
    
    cout << "\nEx7: Invoke All" << endl;
    exercise7();
    
    cout << "\nEx8: Make Array" << endl;
    exercise8();
    
    return 0;
}

// ============================================================
// ANSWERS
// ============================================================
/*
Ex1:
void printLine() { cout << endl; }
template<typename T>
void printLine(T val) { cout << val << endl; }
template<typename T, typename... Args>
void printLine(T first, Args... rest) {
    cout << first << " | ";
    printLine(rest...);
}

Ex2:
template<typename... Args>
auto sumAll(Args... args) { return (... + args); }
template<typename... Args>
auto productAll(Args... args) { return (... * args); }
template<typename T, typename... Args>
auto minAll(T first, Args... rest) {
    if constexpr (sizeof...(rest) == 0) return first;
    else { auto m = minAll(rest...); return first < m ? first : m; }
}

Ex3:
template<typename T>
string getTypeInfo() {
    if constexpr (is_integral_v<T>) return "integral";
    else if constexpr (is_floating_point_v<T>) return "floating";
    else if constexpr (is_pointer_v<T>) return "pointer";
    else return "other";
}

Ex4:
template<typename T>
auto safeDivide(T a, T b) {
    static_assert(is_arithmetic_v<T>);
    if (b == 0) return T{0};
    return a / b;
}

Ex5:
template<unsigned Base, unsigned Exp>
struct Power {
    static constexpr unsigned value = Base * Power<Base, Exp-1>::value;
};
template<unsigned Base>
struct Power<Base, 0> {
    static constexpr unsigned value = 1;
};

Ex6:
template<typename T, typename... Types>
struct CountType;
template<typename T>
struct CountType<T> { static constexpr int value = 0; };
template<typename T, typename First, typename... Rest>
struct CountType<T, First, Rest...> {
    static constexpr int value = 
        (is_same_v<T, First> ? 1 : 0) + CountType<T, Rest...>::value;
};

Ex7:
template<typename Arg, typename... Funcs>
void invokeAll(Arg arg, Funcs... funcs) {
    (funcs(arg), ...);
}

Ex8:
template<typename... Args>
auto makeArray(Args... args) {
    using CT = common_type_t<Args...>;
    return array<CT, sizeof...(args)>{static_cast<CT>(args)...};
}
*/
Exercises - C++ Tutorial | DeepML