cpp

exercises

exercises.cpp⚙️
/**
 * Modern C++ Features - Exercises (C++17/20/23)
 * 
 * Compile:
 *   C++17: g++ -std=c++17 -Wall exercises.cpp -o exercises
 *   C++20: g++ -std=c++20 -Wall exercises.cpp -o exercises
 *   C++23: g++ -std=c++23 -Wall exercises.cpp -o exercises
 */

#include <iostream>
#include <vector>
#include <memory>
#include <optional>
#include <variant>
#include <string>
#include <string_view>
#include <map>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <numeric>
#include <array>
using namespace std;

// ============================================================
// Exercise 1: Smart Pointer Factory ⭐⭐
// ============================================================

// TODO: Create factory function that returns unique_ptr
// to different shapes based on type string

void exercise1() {
    // auto shape = createShape("circle");
    // shape->draw();  // "Drawing circle"
    cout << "(Implement shape factory with unique_ptr)" << endl;
}

// ============================================================
// Exercise 2: Lambda Sorter ⭐⭐
// ============================================================

// TODO: Create function that takes vector and sort criteria lambda
// Sort by different criteria: by value, by abs, by last digit

void exercise2() {
    // vector<int> v = {-5, 2, -3, 1, -4};
    // sortBy(v, /* lambda for ascending */);
    // sortBy(v, /* lambda for abs value */);
    cout << "(Implement generic sortBy with lambdas)" << endl;
}

// ============================================================
// Exercise 3: Optional Chain ⭐⭐
// ============================================================

// TODO: Create functions that return optional and chain them
// User -> getAddress() -> getZipCode() -> optional<string>

void exercise3() {
    // auto zip = getUser(1)
    //     .and_then(getAddress)
    //     .and_then(getZipCode);
    cout << "(Implement optional chaining)" << endl;
}

// ============================================================
// Exercise 4: Variant Calculator ⭐⭐⭐
// ============================================================

// TODO: Use variant to represent different operation types
// variant<Add, Sub, Mul, Div> and visit to calculate

void exercise4() {
    // Operation op = Add{};
    // cout << calculate(op, 10, 5);  // 15
    // op = Mul{};
    // cout << calculate(op, 10, 5);  // 50
    cout << "(Implement variant calculator)" << endl;
}

// ============================================================
// Exercise 5: Move-Only Type ⭐⭐⭐
// ============================================================

// TODO: Create class that can only be moved, not copied
// Like unique_ptr but for a custom resource

void exercise5() {
    // UniqueResource r1("file.txt");
    // UniqueResource r2 = r1;      // ERROR: deleted
    // UniqueResource r3 = move(r1); // OK
    cout << "(Implement move-only type)" << endl;
}

// ============================================================
// Exercise 6: String_View Parser ⭐⭐⭐
// ============================================================

// TODO: Parse CSV line using string_view (no allocations)
// Return vector of string_view for each field

void exercise6() {
    // string line = "name,age,city";
    // auto fields = parseCSV(line);
    // fields[0] = "name", fields[1] = "age", etc.
    cout << "(Implement string_view CSV parser)" << endl;
}

// ============================================================
// Exercise 7: Constexpr Math ⭐⭐⭐
// ============================================================

// TODO: Create constexpr functions:
// - power(base, exp)
// - isPrime(n)
// - gcd(a, b)

void exercise7() {
    // constexpr int p = power(2, 10);    // 1024
    // constexpr bool prime = isPrime(17); // true
    // constexpr int g = gcd(48, 18);     // 6
    cout << "(Implement constexpr math functions)" << endl;
}

// ============================================================
// Exercise 8: Smart Container ⭐⭐⭐
// ============================================================

// TODO: Create container that stores shared_ptr to items
// and tracks weak_ptr references for cache behavior

void exercise8() {
    // SmartCache<Widget> cache;
    // auto w1 = cache.get(1);  // Creates new
    // auto w2 = cache.get(1);  // Returns same
    // cache.cleanup();         // Remove expired
    cout << "(Implement smart container with weak_ptr)" << endl;
}

// ============================================================
// Exercise 9: Concept-Constrained Container ⭐⭐⭐ (C++20)
// ============================================================

// TODO: Create a container class that only accepts numeric types
// Use concepts to constrain the template parameter
// Methods: add(), sum(), average(), min(), max()

void exercise9() {
    // NumericContainer<int> ints;
    // ints.add(1).add(2).add(3);
    // cout << ints.sum();      // 6
    // cout << ints.average();  // 2.0
    
    // NumericContainer<string> strs;  // Should fail to compile!
    cout << "(Implement concept-constrained numeric container)" << endl;
}

// ============================================================
// Exercise 10: Range Pipeline ⭐⭐⭐ (C++20)
// ============================================================

// TODO: Create custom range adaptors/views:
// 1. squared - transforms each element to its square
// 2. evens_only - filters only even numbers  
// 3. clamped(min, max) - clamps values to range

void exercise10() {
    // vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    // 
    // C++20 style:
    // auto result = v 
    //     | evens_only()
    //     | squared()
    //     | clamped(0, 50);
    // // Result: {4, 16, 36, 50, 50} (64 and 100 clamped to 50)
    cout << "(Implement custom range adaptors)" << endl;
}

// ============================================================
// Exercise 11: Expected-Based Parser ⭐⭐⭐ (C++23)
// ============================================================

// TODO: Create a JSON-like parser that returns expected
// Parse: {"name": "John", "age": 30}
// Return expected<JsonObject, ParseError>

void exercise11() {
    // auto result = parseJson("{\"name\": \"John\"}");
    // if (result) {
    //     cout << result->get<string>("name");  // "John"
    // } else {
    //     cout << "Error: " << result.error().message;
    // }
    cout << "(Implement expected-based JSON parser)" << endl;
}

// ============================================================
// Exercise 12: Coroutine Generator ⭐⭐⭐⭐ (C++20)
// ============================================================

// TODO: Create a generator coroutine that yields:
// 1. Fibonacci sequence
// 2. Prime numbers
// 3. Custom range with step

void exercise12() {
    // for (int n : fibonacci_generator() | take(10)) {
    //     cout << n << " ";  // 0 1 1 2 3 5 8 13 21 34
    // }
    // 
    // for (int p : prime_generator() | take(5)) {
    //     cout << p << " ";  // 2 3 5 7 11
    // }
    cout << "(Implement coroutine generators)" << endl;
}

// ============================================================
// Exercise 13: Span-Based Matrix ⭐⭐⭐ (C++20)
// ============================================================

// TODO: Create a matrix class that uses span for views
// Support row/column views without copying

void exercise13() {
    // int data[] = {1,2,3,4,5,6,7,8,9};
    // Matrix<3,3> mat(data);
    // 
    // auto row1 = mat.row(0);     // span<int, 3>: {1,2,3}
    // auto col1 = mat.column(0);  // {1,4,7} (may need copying)
    // auto sub = mat.submatrix(0,0,2,2);  // Top-left 2x2
    cout << "(Implement span-based matrix views)" << endl;
}

// ============================================================
// Exercise 14: Three-Way Comparison ⭐⭐ (C++20)
// ============================================================

// TODO: Implement spaceship operator for:
// 1. Semantic version (major.minor.patch)
// 2. Case-insensitive string comparison
// 3. Partial ordering for floating point with NaN handling

void exercise14() {
    // SemVer v1{1, 2, 3}, v2{1, 3, 0};
    // cout << (v1 < v2);   // true
    // cout << (v1 == v2);  // false
    // 
    // CIString s1{"Hello"}, s2{"HELLO"};
    // cout << (s1 == s2);  // true (case-insensitive)
    cout << "(Implement three-way comparison operators)" << endl;
}

// ============================================================
// Exercise 15: Format String Builder ⭐⭐⭐ (C++20)
// ============================================================

// TODO: Create a custom type that can be formatted with std::format
// Support format specifiers like width, alignment, fill character

void exercise15() {
    // Money m{123, 45};  // $123.45
    // 
    // cout << format("{}", m);        // "$123.45"
    // cout << format("{:>15}", m);    // "        $123.45"
    // cout << format("{:*^15}", m);   // "****$123.45****"
    // cout << format("{:.0}", m);     // "$123" (no cents)
    cout << "(Implement custom std::format support)" << endl;
}

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

int main() {
    cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║         MODERN C++ EXERCISES (C++17/20/23)                    ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n=== C++17 Exercises ===" << endl;
    
    cout << "\nEx1: Smart Pointer Factory" << endl;
    exercise1();
    
    cout << "\nEx2: Lambda Sorter" << endl;
    exercise2();
    
    cout << "\nEx3: Optional Chain" << endl;
    exercise3();
    
    cout << "\nEx4: Variant Calculator" << endl;
    exercise4();
    
    cout << "\nEx5: Move-Only Type" << endl;
    exercise5();
    
    cout << "\nEx6: String_View Parser" << endl;
    exercise6();
    
    cout << "\nEx7: Constexpr Math" << endl;
    exercise7();
    
    cout << "\nEx8: Smart Container" << endl;
    exercise8();
    
    cout << "\n=== C++20 Exercises ===" << endl;
    
    cout << "\nEx9: Concept-Constrained Container" << endl;
    exercise9();
    
    cout << "\nEx10: Range Pipeline" << endl;
    exercise10();
    
    cout << "\nEx12: Coroutine Generator" << endl;
    exercise12();
    
    cout << "\nEx13: Span-Based Matrix" << endl;
    exercise13();
    
    cout << "\nEx14: Three-Way Comparison" << endl;
    exercise14();
    
    cout << "\nEx15: Format String Builder" << endl;
    exercise15();
    
    cout << "\n=== C++23 Exercises ===" << endl;
    
    cout << "\nEx11: Expected-Based Parser" << endl;
    exercise11();
    
    return 0;
}

// ============================================================
// ANSWERS
// ============================================================
/*
Ex1:
struct Shape { virtual void draw() = 0; virtual ~Shape() = default; };
struct Circle : Shape { void draw() override { cout << "Circle" << endl; } };
struct Square : Shape { void draw() override { cout << "Square" << endl; } };
unique_ptr<Shape> createShape(string_view type) {
    if (type == "circle") return make_unique<Circle>();
    if (type == "square") return make_unique<Square>();
    return nullptr;
}

Ex2:
template<typename Compare>
void sortBy(vector<int>& v, Compare comp) {
    sort(v.begin(), v.end(), comp);
}
// Usage:
sortBy(v, [](int a, int b) { return a < b; });
sortBy(v, [](int a, int b) { return abs(a) < abs(b); });

Ex5:
class UniqueResource {
    string resource;
public:
    UniqueResource(string r) : resource(move(r)) {}
    UniqueResource(const UniqueResource&) = delete;
    UniqueResource& operator=(const UniqueResource&) = delete;
    UniqueResource(UniqueResource&& o) noexcept : resource(move(o.resource)) {}
    UniqueResource& operator=(UniqueResource&& o) noexcept {
        resource = move(o.resource);
        return *this;
    }
};

Ex6:
vector<string_view> parseCSV(string_view line) {
    vector<string_view> fields;
    size_t start = 0;
    while (start < line.size()) {
        size_t end = line.find(',', start);
        if (end == string_view::npos) end = line.size();
        fields.push_back(line.substr(start, end - start));
        start = end + 1;
    }
    return fields;
}

Ex7:
constexpr int power(int base, int exp) {
    int result = 1;
    for (int i = 0; i < exp; i++) result *= base;
    return result;
}
constexpr bool isPrime(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) return false;
    return true;
}
constexpr int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

Ex9: Concept-Constrained Container (C++20)
#include <concepts>

template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template<Numeric T>
class NumericContainer {
    std::vector<T> data_;
public:
    NumericContainer& add(T value) { 
        data_.push_back(value); 
        return *this; 
    }
    
    T sum() const { 
        return std::accumulate(data_.begin(), data_.end(), T{}); 
    }
    
    double average() const { 
        return static_cast<double>(sum()) / data_.size(); 
    }
    
    T min() const { 
        return *std::min_element(data_.begin(), data_.end()); 
    }
    
    T max() const { 
        return *std::max_element(data_.begin(), data_.end()); 
    }
};

Ex14: Three-Way Comparison (C++20)
#include <compare>

struct SemVer {
    int major, minor, patch;
    
    auto operator<=>(const SemVer&) const = default;
    // Generates all 6 comparison operators!
};

struct CIString {
    std::string value;
    
    std::weak_ordering operator<=>(const CIString& other) const {
        auto toLower = [](char c) { return std::tolower(c); };
        auto it1 = value.begin(), it2 = other.value.begin();
        
        while (it1 != value.end() && it2 != other.value.end()) {
            auto c1 = toLower(*it1++), c2 = toLower(*it2++);
            if (c1 < c2) return std::weak_ordering::less;
            if (c1 > c2) return std::weak_ordering::greater;
        }
        
        if (value.size() < other.value.size()) return std::weak_ordering::less;
        if (value.size() > other.value.size()) return std::weak_ordering::greater;
        return std::weak_ordering::equivalent;
    }
    
    bool operator==(const CIString& other) const {
        return (*this <=> other) == std::weak_ordering::equivalent;
    }
};

Ex15: Format String Builder (C++20)
#include <format>

struct Money {
    int dollars;
    int cents;
};

template<>
struct std::formatter<Money> {
    bool showCents = true;
    
    constexpr auto parse(std::format_parse_context& ctx) {
        auto it = ctx.begin();
        if (it != ctx.end() && *it == '.') {
            ++it;
            if (it != ctx.end() && *it == '0') {
                showCents = false;
                ++it;
            }
        }
        return it;
    }
    
    auto format(const Money& m, std::format_context& ctx) const {
        if (showCents) {
            return std::format_to(ctx.out(), "${}.{:02}", m.dollars, m.cents);
        }
        return std::format_to(ctx.out(), "${}", m.dollars);
    }
};
*/
Exercises - C++ Tutorial | DeepML