├── LICENSE ├── README.md ├── callback1.cc ├── callback2.cc ├── callback3.cc └── callback4.cc /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Michael Egli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Callbacks in C++ 2 | ================ 3 | 4 | Overview 5 | -------- 6 | 7 | The examples in this repository show how callbacks can be implemented in C++. 8 | A C++11 capable compiler is required, such as `GCC` or `Clang`. 9 | 10 | The first example shows how `std::function` can be used as a callback. This is 11 | a common approach that is simple and works in many cases. 12 | 13 | The second example shows how `std::function` callbacks can be stored in a 14 | collection (an `std::vector` in this case). 15 | 16 | The third example shows how to create overloaded wrapper functions to invoke 17 | different types of callbacks. 18 | 19 | The fourth example shows how different types of callbacks (i.e. callbacks with 20 | different types of arguments) can be stored in a single collection (a 21 | `std::map` in this case). 22 | 23 | Please see the implementation in the respective files. You may use the example 24 | code freely in your code. 25 | 26 | Compilation 27 | ----------- 28 | 29 | Each example file is a self contained C++ program with a `main()` function. The 30 | following command can be used to compile and run the examples. The command is for 31 | the first example and the `Clang` compiler. 32 | 33 | ~~~ 34 | clang++ -std=c++11 -o callback1 callback1.cc 35 | ./callback1 36 | ~~~ 37 | -------------------------------------------------------------------------------- /callback1.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * \file callback1.cc 3 | * \author Michael Egli 4 | * \date 08-Mar-2015 5 | * \copyright 2015 wisol technologie GmbH 6 | * 7 | * Overview 8 | * ======== 9 | * 10 | * Shows how to use `std::function` as a callback. 11 | * 12 | * A nice property of `std::function` is that it can bind to anything callable. 13 | * Here we show how to call a free function, a member function (method), and a 14 | * lambda type. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | namespace { 21 | 22 | using cb1_t = std::function; 23 | using cb2_t = std::function; 24 | 25 | void foo1() 26 | { 27 | std::cout << "foo1 is called\n"; 28 | } 29 | 30 | void foo2(int i) 31 | { 32 | std::cout << "foo2 is called with: " << i << "\n"; 33 | } 34 | 35 | struct S { 36 | void foo3() 37 | { 38 | std::cout << "foo3 is called.\n"; 39 | } 40 | }; 41 | 42 | } // end anonymous namespace 43 | 44 | int main() 45 | { 46 | // Bind a free function. 47 | cb1_t f1 = std::bind(&foo1); 48 | // Invoke the function foo1. 49 | f1(); 50 | 51 | // Bind a free function with an int argument. 52 | // Note that the argument can be specified with bind directly. 53 | cb1_t f2 = std::bind(&foo2, 5); 54 | // Invoke the function foo2. 55 | f2(); 56 | 57 | // Bind a function with a placeholder. 58 | cb2_t f3 = std::bind(&foo2, std::placeholders::_1); 59 | // Invoke the function with an argument. 60 | f3(42); 61 | 62 | // Bind a member function. 63 | S s; 64 | cb1_t f4 = std::bind(&S::foo3, &s); 65 | // Invoke the method foo3. 66 | f4(); 67 | 68 | // Bind a lambda. 69 | cb1_t f5 = std::bind([] { std::cout << "lambda is called\n"; }); 70 | f5(); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /callback2.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * \file callback2.cc 3 | * \author Michael Egli 4 | * \date 08-Mar-2015 5 | * \copyright 2015 wisol technologie GmbH 6 | * 7 | * Overview 8 | * ======== 9 | * 10 | * Shows how to store callbacks in a `std::vector`. 11 | * 12 | * Here we use a single type of callback. This limits what we can store in the 13 | * vector, but is enough in many cases. Also note that known arguments can be 14 | * bound and are not part of the type. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace { 22 | 23 | using cb1_t = std::function; 24 | using callbacks_t = std::vector; 25 | 26 | callbacks_t callbacks; 27 | 28 | void foo1() 29 | { 30 | std::cout << "foo1 is called\n"; 31 | } 32 | 33 | void foo2(int i) 34 | { 35 | std::cout << "foo2 is called with: " << i << "\n"; 36 | } 37 | 38 | } // end anonymous namespace 39 | 40 | int main() 41 | { 42 | // Bind a free function. 43 | cb1_t f1 = std::bind(&foo1); 44 | callbacks.push_back(f1); 45 | 46 | // Bind a free function with an int argument. 47 | // Here the argument is statically known. 48 | cb1_t f2 = std::bind(&foo2, 5); 49 | callbacks.push_back(f2); 50 | 51 | // Bind a free function with an int argument. 52 | // Here the argument is bound and can be changed at runtime. 53 | int n = 15; 54 | cb1_t f3 = std::bind(&foo2, std::cref(n)); 55 | callbacks.push_back(f3); 56 | 57 | // Invoke the functions 58 | for(auto& fun : callbacks) { 59 | fun(); 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /callback3.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * \file callback3.cc 3 | * \author Michael Egli 4 | * \date 08-Mar-2015 5 | * \copyright 2015 wisol technologie GmbH 6 | * 7 | * Overview 8 | * ======== 9 | * 10 | * Shows how to create a wrapper function that invokes arbitrary callback. 11 | * 12 | * The callbacks may have return values and arguments. In contrast to the 13 | * examples in `callback1.cc` and `callback2.cc`, we use a function to invoke 14 | * the callback, instead of directly calling it. 15 | * 16 | * The purpose of this wrapper function is to show how such a function can be 17 | * overloaded to take different arguments. In our example, the wrapper 18 | * functions taking plain functions wrap them in a `std::function`. This is not 19 | * necessary for calling the function, but is sometimes required in order to 20 | * store the callback. 21 | * 22 | * Another example shows how to create a wrapper function for a lambda 23 | * type. It uses the fact that the language allows for a conversion of a 24 | * lambda type that doesn't capture to a function pointer. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | namespace { 31 | 32 | using cb1_t = std::function; 33 | using cb2_t = std::function; 34 | 35 | // Wrapper function with std::function without arguments. 36 | template 37 | void call(std::function f) 38 | { 39 | f(); 40 | } 41 | 42 | // Wrapper function with std::function with arguments. 43 | template 44 | void call(std::function f, A... args) 45 | { 46 | f(args...); 47 | } 48 | 49 | // Wrapper function for generic callable object without arguments. 50 | // Delegates to the std::function call. 51 | template 52 | void call(R f(void)) 53 | { 54 | call(std::function(f)); 55 | } 56 | 57 | // Wrapper function for generic callable object with arguments. 58 | // Delegates to the std::function call. 59 | template 60 | void call(R f(A...), A... args) 61 | { 62 | call(std::function(f), args...); 63 | } 64 | 65 | // Wrapper for a function pointer (e.g. a lambda without capture) without 66 | // arguments. 67 | using fp = void (*)(void); 68 | void call(fp f) 69 | { 70 | call(std::function(f)); 71 | } 72 | 73 | void foo1() 74 | { 75 | std::cout << "foo1 is called\n"; 76 | } 77 | 78 | void foo2(int i) 79 | { 80 | std::cout << "foo2 is called with: " << i << "\n"; 81 | } 82 | 83 | } // end anonymous namespace 84 | 85 | int main() 86 | { 87 | // Call function 1. 88 | call(&foo1); 89 | 90 | // Alternative to call function 1. 91 | cb1_t f1 = std::bind(&foo1); 92 | call(f1); 93 | 94 | // Call function 2. 95 | call(&foo2, 5); 96 | 97 | // Alternative to call function 2. 98 | cb2_t f2 = std::bind(&foo2, std::placeholders::_1); 99 | call(f2, 5); 100 | 101 | // Here is an example with a lambda. It calls the function that takes a 102 | // function pointer. 103 | call([] { std::cout << "lambda called\n"; }); 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /callback4.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * \file callback3.cc 3 | * \author Michael Egli 4 | * \date 08-Mar-2015 5 | * \copyright 2015 wisol technologie GmbH 6 | * 7 | * Overview 8 | * ======== 9 | * 10 | * Shows how to store callbacks with different arguments in a collection. 11 | * 12 | * This is an example how `std::function` can be used to store different types 13 | * of callbacks in a single collection. This is often useful to be able to pass 14 | * parameters back to the caller. 15 | * 16 | * The idea is to store an emtpy base type in a collection. This base type is 17 | * then specialized for the different types of callbacks by deriving from it. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace { 27 | 28 | // The base type that is stored in the collection. 29 | struct Func_t { 30 | virtual ~Func_t() = default; 31 | }; 32 | // The map that stores the callbacks. 33 | using callbacks_t = std::map>; 34 | callbacks_t callbacks; 35 | 36 | // The derived type that represents a callback. 37 | template 38 | struct Cb_t : public Func_t { 39 | using cb = std::function; 40 | cb callback; 41 | Cb_t(cb p_callback) : callback(p_callback) {} 42 | }; 43 | 44 | // Wrapper function to call the callback stored at the given index with the 45 | // passed argument. 46 | template 47 | void call(std::type_index index, A&& ... args) 48 | { 49 | using func_t = Cb_t; 50 | using cb_t = std::function; 51 | const Func_t& base = *callbacks[index]; 52 | const cb_t& fun = static_cast(base).callback; 53 | fun(std::forward(args)...); 54 | } 55 | 56 | } // end anonymous namespace 57 | 58 | void foo1() 59 | { 60 | std::cout << "foo1 is called.\n"; 61 | } 62 | 63 | void foo2(int i) 64 | { 65 | std::cout << "foo2 is called with: " << i << "\n"; 66 | } 67 | 68 | void foo3(std::string s, int i) 69 | { 70 | std::cout << "foo3 is called with: " << s << " and: " << i << "\n"; 71 | } 72 | 73 | int main() 74 | { 75 | // Define our functions. 76 | using func1 = Cb_t<>; 77 | std::unique_ptr f1(new func1(&foo1)); 78 | using func2 = Cb_t; 79 | std::unique_ptr f2(new func2(&foo2)); 80 | using func3 = Cb_t; 81 | std::unique_ptr f3(new func3(&foo3)); 82 | 83 | // Add the to the map. 84 | std::type_index index1(typeid(f1)); 85 | std::type_index index2(typeid(f2)); 86 | std::type_index index3(typeid(f3)); 87 | callbacks.insert(callbacks_t::value_type(index1, std::move(f1))); 88 | callbacks.insert(callbacks_t::value_type(index2, std::move(f2))); 89 | callbacks.insert(callbacks_t::value_type(index3, std::move(f3))); 90 | 91 | // Call the callbacks. 92 | call(index1); 93 | call(index2, 5); 94 | call(index3, std::string("an answer of"), 42); 95 | 96 | return 0; 97 | } 98 | --------------------------------------------------------------------------------