#include <iostream>
#include <functional>
#include <vector>
#include <string>
#include <memory>

// A data structure passed to our handlers
struct NetworkEvent {
    int statusCode;
    std::string payload;
};

// 1. Regular Free Function
void logEventToConsole(const NetworkEvent& event) {
    std::cout << "[Console Logger] Status: " << event.statusCode 
              << " | Data: " << event.payload << "\n";
}

// 2. A Class with Member Functions we want to target
class DatabaseSaver {
public:
    void saveToTableA(const NetworkEvent& event) {
        std::cout << "[DB Saver] Saving to Table A -> " << event.payload << "\n";
    }

    void saveToTableB(const NetworkEvent& event, const std::string& schema) {
        std::cout << "[DB Saver] Saving to Table B (" << schema << ") -> " << event.payload << "\n";
    }
};

// 3. An Event Manager that stores and executes dynamic callbacks
class NetworkEventManager {
private:
    // A vector holding different handlers matching the exact same signature
    std::vector<std::function<void(const NetworkEvent&)>> handlers;

public:
    // Register any callable object matching the signature
    void registerHandler(std::function<void(const NetworkEvent&)> handler) {
        if (handler) { // std::function can be explicitly checked if it contains a target
            handlers.push_back(handler);
        }
    }

    // Broadcast an event to all registered targets
    void broadcast(const NetworkEvent& event) {
        std::cout << "\n--- Broadcasting Event (" << event.statusCode << ") ---\n";
        for (const auto& handler : handlers) {
            handler(event); // Invoke the wrapper
        }
    }
};

int main() {
    NetworkEventManager manager;
    DatabaseSaver dbSaver;

    // --- Usage 1: Free Function Pointer ---
    manager.registerHandler(logEventToConsole);

    // --- Usage 2: Stateful Lambda (Capturing local context) ---
    int executionCount = 0;
    manager.registerHandler([&executionCount](const NetworkEvent& event) {
        executionCount++;
        std::cout << "[Stateful Lambda] Runs: " << executionCount 
                  << " | Processing length: " << event.payload.length() << "\n";
    });

    // --- Usage 3: Non-static Class Member Function (Using a Lambda Wrapper) ---
    // This is the preferred modern C++ way to point to a specific object's method
    manager.registerHandler(([&dbSaver](const NetworkEvent& event) {
        dbSaver.saveToTableA(event);
    }));

    // --- Usage 4: Member Function with Extra Arguments (Using std::bind) ---
    // std::placeholders::_1 maps the first argument of the std::function invocation to the member function
    manager.registerHandler(std::bind(&DatabaseSaver::saveToTableB, &dbSaver, std::placeholders::_1, "PROD_SCHEMA"));

    // --- Fire events to demonstrate polymorphism in action ---
    NetworkEvent event1{200, "User Login Success"};
    NetworkEvent event2{404, "Resource Not Found"};

    manager.broadcast(event1);
    manager.broadcast(event2);

    // --- Advanced Check: Empty/Null state safety ---
    std::function<void(const NetworkEvent&)> emptyFunc = nullptr;
    if (!emptyFunc) {
        std::cout << "\n[Safety Check] emptyFunc is safely uninitialized, won't throw std::bad_function_call\n";
    }

    return 0;
}

results matching ""

    No results matching ""