// Callback_19.cpp : Diese Datei enthält die Funktion "main". Hier beginnt und endet die Ausführung des Programms. // #include /** * Example code for: * - callback storage with std::vector * - use of std::function * - use of std::bind * - use of lambda function as callback */ #include #include #include #include /** * Basic std::function callback example. Templated on a function signature * that takes in a uint32_t and returns void. */ struct myData { uint8_t myAge = 55; const char* pchar = "myData struct"; enum en_sex { MALE, FEMALE, DIVERS } sex = MALE; }; typedef std::function cb_t; #if BASICDRIVER /** * Basic example. Constructed with a uint32_t. * Callbacks are passed this uint32_t. */ class BasicDriver { public: BasicDriver(uint32_t val) : val_(val), callbacks_() { } // Register a callback. void register_callback(const cb_t& cb) { // add callback to end of callback list callbacks_.push_back(cb); } /// Call all the registered callbacks. void callback() const { // iterate through callback list and call each one for (const auto& cb : callbacks_) { cb(val_); } } private: /// Integer to pass to callbacks. uint32_t val_; /// List of callback functions. std::vector callbacks_; }; #endif #if ARGDRIVER /** * Here's an example type that stores a std::function and an argument * to pass with that callback. Passing a uint32_t input to your callback * is a pretty common implementation. Also useful if you need to store a * pointer for use with a BOUNCE function. */ struct cb_arg_t { // the callback - takes a uint32_t input. std::function cb; // value to return with the callback. uint32_t arg; }; /** * Arg based example. * Callbacks register with a uint32_t that they want returned * Callbacks always passed their specific uint32_t value */ class ArgDriver { public: ArgDriver() : callbacks_() { } // Register a callback. void register_callback(const cb_t& cb, const uint32_t val) { // add callback to end of callback list callbacks_.push_back({ cb, val }); } /// Call all the registered callbacks. void callback() const { // iterate through callback list and call each one for (const auto& cb : callbacks_) { cb.cb(cb.arg); } } private: /// List of callback functions. std::vector callbacks_; }; #endif /** * Alternative storage implementation. Perhaps you want to store * callbacks for different event types? */ enum my_events_t { VIDEO_STOP = 0, VIDEO_START, VIDEO_PAUS, EVENT_MAX }; struct cb_event_t { std::function cb; my_events_t event; }; /** * Event based example. Constructed with a uint32_t. * Callbacks are passed this uint32_t. * Callbacks are only invoked when their event type matches the * occuring event. */ class EventDriver { public: EventDriver(myData& val) : val_(val), callbacks_() { } // Register a callback. void register_callback(const cb_t& cb, const my_events_t event) { // add callback to end of callback list callbacks_.push_back({ cb, event }); } /// Call all the registered callbacks. void callback(myData& val, my_events_t event) const { // my_events_t event = VIDEO_START; // iterate through callback list and call each one for (const auto& cb : callbacks_) { if (cb.event == event) { cb.cb(val_); } } } private: /// Integer to pass to callbacks. myData& val_; /// List of callback functions. std::vector callbacks_; }; /*********************************************************************************************************************** * Dummy Client #1 * Uses a static method for a callback. */ class Client1 { public: static void func(myData v) { printf("static member callback: %d\n", v.myAge); } }; /*********************************************************************************************************************** * Dummy Client #2 * Uses an instance method as a callback */ class Client2 { public: void func(myData v) const { printf("instance member callback: %d\n", v.myAge); } }; /*********************************************************************************************************************** * Callback on a c function */ extern "C" { static void c_client_callback(myData v) { printf("C function callback: %d\n", v.myAge); } } int main() { /** * Examples using the basic driver * This is constructed with a specific value * Each callback receives this value */ Client2 c2; myData mydata = { 55, "myData struct", myData::MALE }; #if BASICDRIVER BasicDriver bd(0xDEADBEEF); // create basic driver instance printf("Starting examples using the BasicDriver\n"); // register a lambda function as a callback bd.register_callback([](uint32_t v) { printf("lambda callback: 0x%x\n", v); }); /** * std::bind is used to create a function object using * both the instance and method pointers. This gives you the * callback into the specific object - very useful! * * std::bind keeps specific arguments at a fixed value (or a placeholder) * For our argument here, we keep as a placeholder. */ bd.register_callback(std::bind(&Client2::func, &c2, std::placeholders::_1)); // register a static class method as a callback bd.register_callback(&Client1::func); // register a C function pointer as a callback bd.register_callback(&c_client_callback); // call all the registered callbacks bd.callback(); printf("End of examples using the BasicDriver\n"); #endif /** * Examples using the Event Driver. * Note that some callbacks will not be called - * their event type is different! */ EventDriver ed(mydata); printf("Beginning of examples using the EventDriver\n"); // register a lambda function as a callback ed.register_callback( [&mydata](myData mydata) { printf("lambda callback: %d\n", mydata.myAge); }, VIDEO_START); // register client2 cb using std::bind ed.register_callback(std::bind(&Client2::func, &c2, std::placeholders::_1), VIDEO_START); // register a static class method as a callback ed.register_callback(&Client1::func, VIDEO_STOP); // register a C function pointer as a callback ed.register_callback(&c_client_callback, VIDEO_PAUS); // call all the registered callbacks ed.callback(mydata, VIDEO_START); ed.callback(mydata, VIDEO_STOP); ed.callback(mydata, VIDEO_PAUS); printf("End of examples using the EventDriver\n"); #if ARGDRIVER /** * Examples using the Arg Driver. * Note that each callback registers for its own value */ ArgDriver ad; printf("Beginning of examples using the ArgDriver\n"); // register a lambda function as a callback ad.register_callback( [](uint32_t v) { printf("lambda callback: 0x%x\n", v); }, 0x0); // register client2 cb using std::bind ad.register_callback(std::bind(&Client2::func, &c2, std::placeholders::_1), 0x1); // register a static class method as a callback ad.register_callback(&Client1::func, 0x2); // register a C function pointer as a callback ad.register_callback(&c_client_callback, 0x3); // call all the registered callbacks ad.callback(); printf("End of examples using the ArgDriver\n"); #endif return 0; }