第12课 std::bind和std::function(3)_std::function可调用对象包装器
Posted on 2017-10-07 18:08 浅墨浓香 阅读(872) 评论(0) 编辑 收藏 举报1. std::function
(1)首先是一个类模板,用于包装可调用对象。可以容纳除了类成员(函数)指针之外的所有可调用对象。
(2)可以将普通函数,lambda表达式和函数对象类统一起来。尽管它们并不是相同的类型,但通过function类模板,可以转化为相同类型的对象(function对象),这样就可以用统一的方式来保存或传递可调用对象。
(3)实现了一套类型消除机制,可用统一的方式处理不同类型的可调用对象。
(4)std::function进一步深化以数据为中心(封装)的面向对象思想(连函数都对象化了)
【编程实验】std::function作为函数的入参(“万能类型”)
#include <iostream> #include <functional> //for std::bind & std::function using namespace std; using namespace std::placeholders; //传统C函数 int func(int a, int b) { return a + b; } //仿函数 class Functor { public: int operator()(int a, int b) { return a - b; } }; //类的成员函数 class Foo { public: static int func(int a, int b) { return a * b; } int func_common(int a, int b) { return a * b; } }; //模板函数 template < typename T> auto template_func (T a ,T b)->decltype(a + b) { return a + b; } //测试函数 //1. 这是一个“万能”的函数,可接受不同类型的可调用对象,而不必为他们重载多个版本的test函数 //2. 可以测试的对象包含各类可调用对象,如普通函数、仿函数、lambda表达式等 int test(int x, int y, const std::function<int(int, int)>& callableObjects) { return callableObjects(x, y); } int main() { //传入普通函数 using Fn = int(*)(int, int); Fn fn = &func; //decltype(func)* fn = &func; cout << "func(3, 4): " << test(3, 4, fn) << endl; //普通函数指针可以直接赋值给std::function //测试函数模板 auto tfn = template_func<int>; cout << "template_func<int>(3, 4): " << test(3, 4, tfn) << endl; //测试仿函数 Functor ftor; cout << "Functor(3, 4): " << test(3, 4, ftor) << endl; //仿函数可以直接赋值给std::function //测试lambda表达式 auto lbd = [](int a, int b){ return a + b; }; //lambda表达式可以直接赋值给std::function cout << "[](int a, int b){ return a + b }: " << test(3, 4, lbd) << endl; //测试类的成员函数 auto memfn = Foo::func; //静态成员函数 //静态成员函数可以直接赋值给std::function cout << "Foo::func(3, 4): " << test(3, 4, memfn) << endl; //普通成员函数(不能直接赋值给std::function,需先经bind转成std::function) auto commfn = bind(&Foo::func_common, Foo(), _1, _2);//先转换为std::function cout << "Foo::func_common(3, 4): " << test(3, 4, commfn) << endl; return 0; } /*测试结果 e:\Study\C++11\12>g++ -std=c++11 test1.cpp e:\Study\C++11\12>a.exe func(3, 4): 7 template_func<int>(3, 4): 7 Functor(3, 4): -1 [](int a, int b){ return a + b }: 7 Foo::func(3, 4): 12 Foo::func_common(3, 4): 12 */
2. std::function和std::bind的关系
(1)std::bind是一个函数模板,用于将可调用对象及其参数一起,绑定成一个std::function对象。其返回值是个std::function类型。
(2)std::function是一个类模板,用来包装各类可调用对象为新的callable object。他可以接受全局函数、类的静态成员函数并直接进行封装。但不能直接接受类的非静态成员,需要使用bind绑定才能赋值给std::function。
【编程实验】利用function+bind实现回调函数(类似于函数指针的作用,可保存、延迟处理函数)
#include <iostream> #include <functional> //for std::bind & std::function using namespace std; using namespace std::placeholders; //操作系统 class OperatingSystem { private: using NotifyFunc = std::function<void(string, string)>; NotifyFunc m_callback; public: string jobname; string jobmessage; public: OperatingSystem() : m_callback(nullptr){}; template <typename T1, typename T2> void RegisterNotify(T1 memberFunc, T2* pThis) { m_callback = std::bind(memberFunc, pThis, _1, _2); } template <typename T> void RegisterNotify(T globalFunc) { m_callback = std::bind(globalFunc, _1, _2); } //当作业加入时,会回调作业本身定义的个性化通知! bool Notify() { if(m_callback != NULL) m_callback(jobname, jobmessage); return false; } }; //作业类 class Job { private: //每次作业加入进来,会有个性化的通知 void SendMsg(string name, string msg) { cout <<"(local)"<< name << ": " << msg << endl; } public: string name; string msg; Job(string name, string msg):name(name),msg(msg) { } void addJob(OperatingSystem& os) { os.RegisterNotify(&Job::SendMsg, this); os.jobname = name; os.jobmessage = msg; os.Notify(); } }; void SendMsg(string name, string msg) { cout << "(global)" <<name << ": " << msg << endl; } int main() { OperatingSystem os; //绑定Job类的成员函数 Job job1("job1", "hello world!"); job1.addJob(os); Job job2("job2", "thank you!"); job2.addJob(os); //绑定全局函数 os.RegisterNotify(&SendMsg); os.jobname = "job3"; os.jobmessage = "nice to meet you!"; os.Notify(); return 0; } /*输出结果 e:\Study\C++11\12>g++ -std=c++11 test2.cpp e:\Study\C++11\12>a.exe (local)job1: hello world! (local)job2: thank you! (global)job3: nice to meet you! */