cpp

modern cpp

01_modern_cpp.cpp⚙️
/**
 * ============================================================
 * C++ MODERN FEATURES (C++11/14/17/20)
 * ============================================================
 * 
 * This file covers:
 * - Auto and decltype
 * - Range-based for loops
 * - nullptr and type safety
 * - Move semantics overview
 * - Structured bindings (C++17)
 * - Optional, variant, any (C++17)
 * - Concepts preview (C++20)
 * 
 * Compile: g++ -std=c++17 -Wall 01_modern_cpp.cpp -o modern
 * Run: ./modern
 * 
 * ============================================================
 */

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <tuple>
#include <optional>
#include <variant>
#include <any>
#include <memory>
#include <algorithm>
#include <initializer_list>
#include <type_traits>

using namespace std;

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

int main() {
    cout << "============================================" << endl;
    cout << "     C++ MODERN FEATURES" << endl;
    cout << "============================================" << endl << endl;

    // ========================================================
    // PART 1: AUTO AND TYPE DEDUCTION
    // ========================================================
    
    cout << "--- PART 1: AUTO & TYPE DEDUCTION ---" << endl << endl;
    
    // Basic auto
    auto integer = 42;           // int
    auto floating = 3.14;        // double
    auto text = "hello"s;        // std::string (with s suffix)
    auto cstr = "hello";         // const char*
    
    cout << "auto integer = 42;     // type: int" << endl;
    cout << "auto floating = 3.14;  // type: double" << endl;
    cout << "auto text = \"hello\"s;  // type: std::string" << endl;
    
    // Auto with containers
    vector<int> nums = {1, 2, 3, 4, 5};
    auto it = nums.begin();       // vector<int>::iterator
    auto& ref = nums[0];          // int&
    const auto& cref = nums[1];   // const int&
    
    cout << "\nauto with containers preserves const/ref qualifiers" << endl;
    
    // decltype - get type without evaluating
    int x = 10;
    decltype(x) y = 20;          // int
    decltype((x)) z = x;         // int& (parentheses matter!)
    
    cout << "\ndecltype(x) gives: int" << endl;
    cout << "decltype((x)) gives: int& (note the parens!)" << endl;
    
    // decltype(auto) - perfect forwarding return type
    auto getValue = [](int& v) -> decltype(auto) {
        return v;  // Returns int&, not int
    };
    
    cout << endl;

    // ========================================================
    // PART 2: RANGE-BASED FOR LOOPS
    // ========================================================
    
    cout << "--- PART 2: RANGE-BASED FOR ---" << endl << endl;
    
    vector<string> words = {"Hello", "Modern", "C++"};
    
    // By value (copies)
    cout << "By value: ";
    for (string word : words) {
        cout << word << " ";
    }
    cout << endl;
    
    // By reference (modifiable)
    for (string& word : words) {
        word += "!";
    }
    cout << "Modified: ";
    for (const string& word : words) {  // By const ref (read-only)
        cout << word << " ";
    }
    cout << endl;
    
    // With auto
    cout << "With auto: ";
    for (const auto& word : words) {
        cout << word << " ";
    }
    cout << endl;
    
    // With initializer list
    cout << "With init list: ";
    for (int n : {1, 2, 3, 4, 5}) {
        cout << n << " ";
    }
    cout << endl;
    
    cout << endl;

    // ========================================================
    // PART 3: NULLPTR AND TYPE SAFETY
    // ========================================================
    
    cout << "--- PART 3: NULLPTR ---" << endl << endl;
    
    int* ptr1 = nullptr;   // Correct way
    // int* ptr2 = NULL;   // Old way (avoid)
    // int* ptr3 = 0;      // Really old way (avoid)
    
    // Type safety
    auto checkNull = [](int* p) {
        if (p == nullptr) {
            cout << "Pointer is null" << endl;
        } else {
            cout << "Pointer value: " << *p << endl;
        }
    };
    
    checkNull(ptr1);
    int value = 42;
    checkNull(&value);
    
    // nullptr_t type
    cout << "\nnullptr has type std::nullptr_t" << endl;
    cout << "Convertible to any pointer type" << endl;
    
    cout << endl;

    // ========================================================
    // PART 4: INITIALIZER LISTS
    // ========================================================
    
    cout << "--- PART 4: INITIALIZER LISTS ---" << endl << endl;
    
    // Uniform initialization
    int arr[] = {1, 2, 3, 4, 5};
    vector<int> vec1 = {1, 2, 3, 4, 5};
    vector<int> vec2{1, 2, 3, 4, 5};  // Direct initialization
    
    map<string, int> ages = {
        {"Alice", 30},
        {"Bob", 25}
    };
    
    // Custom class with initializer_list
    class Numbers {
    private:
        vector<int> data;
    public:
        Numbers(initializer_list<int> list) : data(list) {}
        
        void print() const {
            for (int n : data) cout << n << " ";
            cout << endl;
        }
    };
    
    Numbers n = {10, 20, 30, 40};
    cout << "Custom class with initializer_list: ";
    n.print();
    
    // Prevents narrowing conversions
    // int x{3.14};  // ERROR: narrowing conversion
    int safe{42};    // OK
    cout << "Braces prevent narrowing: int x{3.14} won't compile" << endl;
    
    cout << endl;

    // ========================================================
    // PART 5: STRUCTURED BINDINGS (C++17)
    // ========================================================
    
    cout << "--- PART 5: STRUCTURED BINDINGS ---" << endl << endl;
    
    // With pair
    pair<string, int> person = {"Alice", 30};
    auto [name, age] = person;
    cout << "pair: " << name << " is " << age << endl;
    
    // With tuple
    tuple<int, double, string> data = {1, 3.14, "hello"};
    auto [id, value2, text2] = data;
    cout << "tuple: " << id << ", " << value2 << ", " << text2 << endl;
    
    // With map iteration
    map<string, int> scores = {{"Alice", 95}, {"Bob", 87}};
    cout << "map iteration:" << endl;
    for (const auto& [student, score] : scores) {
        cout << "  " << student << ": " << score << endl;
    }
    
    // With arrays
    int numbers[3] = {10, 20, 30};
    auto [a, b, c] = numbers;
    cout << "array: " << a << ", " << b << ", " << c << endl;
    
    // With struct
    struct Point { int x, y; };
    Point p = {100, 200};
    auto [px, py] = p;
    cout << "struct: x=" << px << ", y=" << py << endl;
    
    cout << endl;

    // ========================================================
    // PART 6: OPTIONAL (C++17)
    // ========================================================
    
    cout << "--- PART 6: OPTIONAL ---" << endl << endl;
    
    // Function that may or may not return a value
    auto findUser = [](int id) -> optional<string> {
        map<int, string> users = {{1, "Alice"}, {2, "Bob"}};
        auto it = users.find(id);
        if (it != users.end()) {
            return it->second;
        }
        return nullopt;  // No value
    };
    
    // Using optional
    if (auto user = findUser(1); user.has_value()) {
        cout << "Found user: " << *user << endl;
    }
    
    auto user2 = findUser(99);
    cout << "User 99: " << user2.value_or("Not found") << endl;
    
    // Create optional
    optional<int> opt1;              // Empty
    optional<int> opt2 = 42;         // With value
    optional<int> opt3 = nullopt;    // Explicitly empty
    
    cout << "\nopt1.has_value() = " << opt1.has_value() << endl;
    cout << "opt2.has_value() = " << opt2.has_value() << endl;
    cout << "opt2.value() = " << opt2.value() << endl;
    
    cout << endl;

    // ========================================================
    // PART 7: VARIANT (C++17)
    // ========================================================
    
    cout << "--- PART 7: VARIANT ---" << endl << endl;
    
    // Type-safe union
    variant<int, double, string> v;
    
    v = 42;
    cout << "variant as int: " << get<int>(v) << endl;
    
    v = 3.14;
    cout << "variant as double: " << get<double>(v) << endl;
    
    v = "hello";
    cout << "variant as string: " << get<string>(v) << endl;
    
    // Check which type
    cout << "\nindex() = " << v.index() << " (2 = string)" << endl;
    cout << "holds_alternative<string>: " << holds_alternative<string>(v) << endl;
    
    // Visit pattern
    variant<int, double, string> values[] = {1, 2.5, "text"};
    
    cout << "\nUsing std::visit:" << endl;
    for (const auto& val : values) {
        visit([](auto&& arg) {
            cout << "  Value: " << arg << " (type: " << typeid(arg).name() << ")" << endl;
        }, val);
    }
    
    cout << endl;

    // ========================================================
    // PART 8: ANY (C++17)
    // ========================================================
    
    cout << "--- PART 8: ANY ---" << endl << endl;
    
    // Can hold any type
    any a = 42;
    cout << "any as int: " << any_cast<int>(a) << endl;
    
    a = 3.14;
    cout << "any as double: " << any_cast<double>(a) << endl;
    
    a = string("hello");
    cout << "any as string: " << any_cast<string>(a) << endl;
    
    // Type checking
    cout << "\nhas_value(): " << a.has_value() << endl;
    cout << "type().name(): " << a.type().name() << endl;
    
    // Safe cast
    try {
        int val = any_cast<int>(a);  // Wrong type!
    } catch (const bad_any_cast& e) {
        cout << "bad_any_cast caught: " << e.what() << endl;
    }
    
    // Reset
    a.reset();
    cout << "After reset, has_value(): " << a.has_value() << endl;
    
    cout << endl;

    // ========================================================
    // PART 9: STRING_VIEW (C++17)
    // ========================================================
    
    cout << "--- PART 9: STRING_VIEW ---" << endl << endl;
    
    // Non-owning view of string data
    string s = "Hello, World!";
    string_view sv = s;
    
    cout << "string_view: " << sv << endl;
    cout << "Substring: " << sv.substr(7, 5) << endl;
    
    // No allocation for string literals
    string_view literal = "This is efficient";
    cout << "Literal view: " << literal << endl;
    
    // Useful for function parameters
    auto printView = [](string_view str) {
        cout << "Received: " << str << endl;
    };
    
    printView("C-string");    // No conversion to std::string
    printView(s);             // Works with std::string
    printView(sv);            // Works with string_view
    
    cout << endl;

    // ========================================================
    // PART 10: IF/SWITCH WITH INITIALIZER (C++17)
    // ========================================================
    
    cout << "--- PART 10: IF/SWITCH INITIALIZER ---" << endl << endl;
    
    // if with initializer
    map<string, int> lookup = {{"one", 1}, {"two", 2}};
    
    if (auto it = lookup.find("two"); it != lookup.end()) {
        cout << "Found: " << it->first << " = " << it->second << endl;
    }
    // 'it' is not visible here - limited scope
    
    // switch with initializer
    enum class Status { OK, Error, Pending };
    
    auto getStatus = []() { return Status::OK; };
    
    switch (Status s = getStatus(); s) {
        case Status::OK:
            cout << "Status: OK" << endl;
            break;
        case Status::Error:
            cout << "Status: Error" << endl;
            break;
        case Status::Pending:
            cout << "Status: Pending" << endl;
            break;
    }
    
    cout << endl;

    // ========================================================
    // MODERN C++ SUMMARY
    // ========================================================
    
    cout << "--- MODERN C++ SUMMARY ---" << endl << endl;
    
    cout << "C++11:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• auto, decltype" << endl;
    cout << "• Range-based for" << endl;
    cout << "• Lambda expressions" << endl;
    cout << "• Smart pointers (unique_ptr, shared_ptr)" << endl;
    cout << "• Move semantics" << endl;
    cout << "• nullptr" << endl;
    cout << "• Uniform initialization" << endl;
    
    cout << "\nC++14:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Generic lambdas" << endl;
    cout << "• decltype(auto)" << endl;
    cout << "• make_unique" << endl;
    
    cout << "\nC++17:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Structured bindings" << endl;
    cout << "• if constexpr" << endl;
    cout << "• optional, variant, any" << endl;
    cout << "• string_view" << endl;
    cout << "• Filesystem library" << endl;
    cout << "• if/switch with initializer" << endl;
    
    cout << "\nC++20:" << endl;
    cout << "─────────────────────────────────────────" << endl;
    cout << "• Concepts" << endl;
    cout << "• Ranges" << endl;
    cout << "• Coroutines" << endl;
    cout << "• Modules" << endl;
    cout << "• Three-way comparison (<=>) " << endl;
    
    cout << endl;

    cout << "============================================" << endl;
    cout << "MODERN C++ FEATURES COMPLETE!" << endl;
    cout << "============================================" << endl;

    return 0;
}

// ============================================================
// EXERCISES:
// ============================================================
/*
 * 1. Config parser using optional:
 *    - Parse key=value pairs
 *    - Return optional<string> for lookups
 *    - Support default values
 * 
 * 2. Event system using variant:
 *    - Different event types (Mouse, Keyboard, etc.)
 *    - Use visit for event handling
 *    - Type-safe event dispatch
 * 
 * 3. Property bag using any:
 *    - Store different types by string key
 *    - Type-safe retrieval
 *    - Support for default values
 * 
 * 4. JSON-like value type:
 *    - variant<null_t, bool, int, double, string, array, object>
 *    - Recursive structure for arrays/objects
 *    - Parse/serialize methods
 */
Modern Cpp - C++ Tutorial | DeepML