C++11新特性之 CALLBACKS

最后更新于:2022-04-01 06:32:15

《C++11新特性之std::function》提到了std::function作为回调函数。 今天主要讨论不同情况下std::function作为回调使用。 **使用回调** ~~~ #include <functional> #include <iostream> namespace { using cb1_t = std::function<void()>; using cb2_t = std::function<void(int)>; void foo1() { std::cout << "foo1 is called\n"; } void foo2(int i) { std::cout << "foo2 is called with: " << i << "\n"; } struct S { void foo3() { std::cout << "foo3 is called.\n"; } }; } int main() { // Bind a free function. cb1_t f1 = std::bind(&foo1); // Invoke the function foo1. f1(); // Bind a free function with an int argument. // Note that the argument can be specified with bind directly. cb1_t f2 = std::bind(&foo2, 5); // Invoke the function foo2. f2(); // Bind a function with a placeholder. cb2_t f3 = std::bind(&foo2, std::placeholders::_1); // Invoke the function with an argument. f3(42); // Bind a member function. S s; cb1_t f4 = std::bind(&S::foo3, &s); // Invoke the method foo3. f4(); // Bind a lambda. cb1_t f5 = std::bind([] { std::cout << "lambda is called\n"; }); f5(); return 0; } ~~~ **存储回调**  使用回调是非常好的,但是更多的情况下,我们往往需要存储一些回调函数,并稍后使用。例如,注册一个客户端到某个事件上。(也许注册和事件是C Sharp的词汇) 我们经常使用std::vector来完成任务。  缺点就是,我们不能再vector中存储不同的类型 。  但是,大多数情况下,一种类型就可以满足我们了。 ~~~ #include <vector> #include <functional> #include <iostream> namespace { using cb1_t = std::function<void()>; using callbacks_t = std::vector<cb1_t>; callbacks_t callbacks; void foo1() { std::cout << "foo1 is called\n"; } void foo2(int i) { std::cout << "foo2 is called with: " << i << "\n"; } } // end anonymous namespace int main() { // Bind a free function. cb1_t f1 = std::bind(&foo1); callbacks.push_back(f1); // Bind a free function with an int argument. // Here the argument is statically known. cb1_t f2 = std::bind(&foo2, 5); callbacks.push_back(f2); // Bind a free function with an int argument. // Here the argument is bound and can be changed at runtime. int n = 15; cb1_t f3 = std::bind(&foo2, std::cref(n)); callbacks.push_back(f3); // Invoke the functions for(auto& fun : callbacks) { fun(); } return 0; } ~~~ **包装函数**  上面提到都不是重点,个人觉得特别重要的就是std::function作为函数的参数使用。  下面一个例子就将展示一个函数被copy不同的参数。 Note that we always produce an std::function, even though in some cases we could invoke the target directly. Whether this is required depends on the use case. If all the function does is invoking the target, then directly doing it is more efficient. The reason is that std::function does have some overhead, because it is a polymorphic class. ~~~ #include <functional> #include <iostream> namespace { using cb1_t = std::function<void()>; using cb2_t = std::function<void(int)>; // Wrapper function with std::function without arguments. template<typename R> void call(std::function<R(void)> f) { f(); } // Wrapper function with std::function with arguments. template<typename R, typename ...A> void call(std::function<R(A...)> f, A... args) { f(args...); } // Wrapper function for generic callable object without arguments. // Delegates to the std::function call. template<typename R> void call(R f(void)) { call(std::function<R(void)>(f)); } // Wrapper function for generic callable object with arguments. // Delegates to the std::function call. template<typename R, typename ...A> void call(R f(A...), A... args) { call(std::function<R(A...)>(f), args...); } // Wrapper for a function pointer (e.g. a lambda without capture) without // arguments. using fp = void (*)(void); void call(fp f) { call(std::function<void()>(f)); } void foo1() { std::cout << "foo1 is called\n"; } void foo2(int i) { std::cout << "foo2 is called with: " << i << "\n"; } } // end anonymous namespace int main() { // Call function 1. call(&foo1); // Alternative to call function 1. cb1_t f1 = std::bind(&foo1); call(f1); // Call function 2. call(&foo2, 5); // Alternative to call function 2. cb2_t f2 = std::bind(&foo2, std::placeholders::_1); call(f2, 5); // Here is an example with a lambda. It calls the function that takes a // function pointer. call([] { std::cout << "lambda called\n"; }); return 0; } ~~~
';