第12课 std::bind和std::function(3)_std::function可调用对象包装器
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(, , fn) << endl; //普通函数指针可以直接赋值给std::function //测试函数模板
auto tfn = template_func<int>;
cout << "template_func<int>(3, 4): " << test(, , tfn) << endl; //测试仿函数
Functor ftor;
cout << "Functor(3, 4): " << test(, , 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(, , lbd) << endl; //测试类的成员函数
auto memfn = Foo::func; //静态成员函数
//静态成员函数可以直接赋值给std::function
cout << "Foo::func(3, 4): " << test(, , 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(, , commfn) << endl; return ;
}
/*测试结果
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 ;
}
/*输出结果
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!
*/
第12课 std::bind和std::function(3)_std::function可调用对象包装器的更多相关文章
- std::bind和std::function
std::bind 用于绑定一个函数,返回另外一种调用方式的函数对象 ,可以改变参数顺序 和个数,特别是在多线程的程序中,经常用它将函数进行包装,然后打包发送给工作线程,让工作线程去执行我们的任务. ...
- c++11特性与cocos2d-x 3.0之std::bind与std::function
昨天同事让帮忙写一小功能,才发现cocos2d-x 3.0 和 cocos2d-x 3.0rc0 差别还是相当大的. 发现Label这一个控件,3.0就比rc0版本多了一个创建函数,更为关键的是3.0 ...
- 第11课 std::bind和std::function(2)_std::bind绑定器
1. 温故知新:std::bind1st和std::bind2nd (1)bind1st.bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数.仿函数等)的第1个或第2个参数上. ( ...
- 第10课 std::bind和std::function(1)_可调用对象
1. 几种可调用对象(Callable Objects) (1)普通函数指针或类成员的函数指针 (2)具有operator()成员函数的类对象(仿函数).如c++11中的std::function类模 ...
- std::bind与std::ref, why and how
首先解释下为什么有时候需要bind. 我们可以用bind从函数T add(T a, T b)造出个inc()来,即把b写死为1.这个例子本身比较傻,但有不傻的应用. template<typen ...
- std::function"函数"对象包装器
语义: 类模板std::function是可调用对象的包装器,可以包装除了类成员之外的所有可调用对象.包括,普通函数,函数指针,lambda,仿函数.通过指定的模板参数,它可以用统一的方式保存,并延迟 ...
- 【浅析C++11】std::function和std::bind
目录 std::function可调用对象包装器 std::function基本用法 std::function/std::bind与抽象工厂.工厂方法的一点思考 std::function可调用对象 ...
- std::bind接口与实现
前言 最近想起半年前鸽下来的Haskell,重温了一下忘得精光的语法,读了几个示例程序,挺带感的,于是函数式编程的草就种得更深了.又去Google了一下C++与FP,找到了一份近乎完美的讲义,然后被带 ...
- C++11 std::bind std::function 高级使用方法
从最基础的了解,std::bind和std::function /* * File: main.cpp * Author: Vicky.H * Email: eclipser@163.com */ # ...
随机推荐
- supervisor使用总结
简介: Supervisor是一个进程控制系统. 它是一个C/S系统(注意: 其提供WEB接口给用户查询和控制). 它允许用户去监控和控制在类UNIX系统的进程. 它的目标与launchd.daemo ...
- 集成学习之AdaBoost
AdaBoost 当做出重要决定时,大家可能会考虑吸取多个专家而不只是一个人的意见,机器学习也是如此,这就是集成学习的基本思想.使用集成方法时有多种形式:可以是不同算法的集成,也可以是同一算法在不同设 ...
- mysql之 myloader原理介绍
myloader恢复主要流程 1.首先由myloader主线程完成建库建表,依次将备份目录下建库和建表文件执行应用到目标数据库实例中: 2.接着myloader主线程会生成多个工作线程,由这些 ...
- MySQL之 从复制延迟问题排查
一.从库复制延迟问题 1.可能的原因如下(1)主从服务器处于不同的网络之中,由于网络延迟导致:(2)主从服务器的硬件配置不同,从服务器的硬件配置(包括内存,CPU,网卡等)远低于主服务器:(3)主库上 ...
- Python的rand vs randn以及linspace
Numpy里面的randn是满足了整体分布的,normal distribution(正态分布):rand则是满足了Uniform Distribution(均匀分布): Linspace(start ...
- dojo:如何显示ListBox风格的选择框
常见的选择框控件:Selelct.FilteringSelect和ComboBox都是下拉框风格,而不是ListBox风格. dojo还提供了一个dijit.form.MultiSelect控件可以解 ...
- NET设计模式 第二部分 结构性模式(11):外观模式(Façade Pattern)
外观模式(Façade Pattern) ——.NET设计模式系列之十二 Terrylee,2006年3月 概述 在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着 ...
- golang 原子操作函数
golang中的原子操作在sync/atomic package中. 下文以比较和交换操作函数为例,介绍其使用. CompareAndSwapInt32 比较和交换操作是原子性的. // Compar ...
- 中文自然语言处理工具HanLP源码包的下载使用记录
中文自然语言处理工具HanLP源码包的下载使用记录 这篇文章主要分享的是hanlp自然语言处理源码的下载,数据集的下载,以及将让源代码中的demo能够跑通.Hanlp安装包的下载以及安装其实之前就已经 ...
- RedHat6.5安装Spark单机
版本号: RedHat6.5 RHEL 6.5系统安装配置图解教程(rhel-server-6.5) JDK1.8 http://blog.csdn.net/chongxin1/arti ...