C++11 学习笔记 std::function和bind绑定器
C++11 学习笔记 std::function和bind绑定器
一.std::function
C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法五花八门。为了统一泛化函数对象,函数指针,引用函数,成员函数的指针的各种操作,让我们可以按更统一的方式写出更加泛化的代码,C++11推出了std::function。
std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。
#1include <iostream>
#include <functional> using namespace std; void func(void){
cout << __FUNCTION__ << "(" << a << ") ->: ";
} class Foo
{
public:
static int foo_func(int a){
cout << __FUNCTION__ << "(" << a << ") ->: ";
return a;
}
}; class bar
{
public:
int operator()(int a){
cout << __FUNCTION << "(" << a << ") ->: ";
return a;
}
}; int main(){
//绑定一个普通函数
std::function<void(void)> fry = func;
fr1(); //绑定一个类的静态成员函数
std::function<int(int)> fr2 = Foo::foo_func;
cout << fr2() << endl; //绑定一个仿函数
Bar bar;
fr2 = bar;
cout << fr2() <<endl; return ;
}
std::function的使用方法:我们给std::function填入合适的函数签名(即一个函数类型,只需要包括返回值和参数表)之后,它就变成了一个可以容纳所有这一类调用方式的“函数包装器”。
#include <iostream>
#include <functional> using namespace std; class A
{
public:
A(const std::function<void()>& f){
:callback_(f){} void notify(void){
callback_();
}
private:
std::function<void()> callback_;
}; class Foo
{
public:
void operator()(void){
cout << __FUNCTION__<< endl;
}
}; int main(){
Foo foo;
A aa(foo);
aa.notify(); return ;
}
从上面的例子看,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数,也可以把它看做类似于C#中特殊的委托(只有一个成员的委托)。
#include <iostream>
#include <functional> using namespace std; void call_when_even(int x, const std::function<void(int)>& f){
if(!(x & )){
f(x);
}
} void output(int x){
cout << x <<" ";
} int main(void){
for(int i=;i<;i++){
call_when_even(i, output);
}
cout<<endl; return ;
}
std::function还可以作为函数入参,这样可以在函数外部控制函数的内部行为了,让我们的函数变得更加灵活。
二.std::bind绑定器
std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。通俗来讲,它主要有两大作用:
1).将可调用对象与其参数一起绑定成一个仿函数。
2).将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。
function模板类和bind模板函数,都可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时。
1).std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别)。
2).绑定到类的非静态成员函数,则需要使用std::bind。
#include <iostream>
#include <functional> using namespace std; void call_when_even(int x, const std::function<void(int)>& f){
if(!(x & )){
f(x);
}
} void output(int x){
cout << x << " ";
} void output_add_2(int x){
cout << x + << " ";
} int main(){
{
auto fr = std::bind(output, std::placeholders::_1);
for(int i=;i<;i++){
call_when_even(i, fr);
}
cout << endl;
} {
auto fr = std::bind(output_add_2, std::placeholders::_1);
for(int i=;i<;i++){
call_when_even(i, fr);
}
cout << endl;
} return ;
}
"std::placeholders::_1"是一个占位符对象,用于表示当函数output(output_add_2)通过函数fr进行调用时,函数fr的第一个参数在函数output(output_add_2)的参数列表中的位置。
下面是两个样例:
#include <iostream>
#include <functional> using namespace std; class A
{
public:
int i_=; void output(int x, int y){
cout << x << " " << y <<endl;
}
}; int main(){
A a;
std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1,std::placeholders::_2);
fr(,); std::function<int&(void)> fr_i = std::bind(&A::i_, &a);
fr_i() = ;
cout << a.i_ << endl; return ;
}
//使用组合bind函数,找出集合中大于5小于10的元素个数
#include <iostream>
#include <functional> using namespace std; auto f = std::bind(std::logical_and<bool>(),std::bind(std::greater<int>(),_1,),std::bind(std::less_equal<int>(), _1, )); int main(){
set<int> se={,,,,,,,,};
int count = std::count_if(se.begin(), se.end(), f);
cout << count <<endl; return ;
}
std::bind需要注意的一些事项:(http://www.cnblogs.com/slysky/p/3822640.html)
1).std::bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的
2).对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的
3).bind的返回值是可调用实体,可以直接赋给std::function对象
4).对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的
5).类的this可以通过对象或者指针来绑定
C++11 学习笔记 std::function和bind绑定器的更多相关文章
- c++11——std::function和bind绑定器
c++11中增加了std::function和std::bind,可更加方便的使用标准库,同时也可方便的进行延时求值. 可调用对象 c++中的可调用对象存在以下几类: (1)函数指针 (2)具有ope ...
- 第11课 std::bind和std::function(2)_std::bind绑定器
1. 温故知新:std::bind1st和std::bind2nd (1)bind1st.bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数.仿函数等)的第1个或第2个参数上. ( ...
- C++11学习笔记之三lamda表达式,std::function, std::bind
//lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout ...
- C++11中的std::function
看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed; std::fun ...
- 【转】C++11中的std::function
原文地址:http://www.jellythink.com/archives/771 看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard: ...
- C++中的仿函数,std::function和bind()的用法
1.仿函数:又叫std::function,是C++中的一个模板类 2.C语言中的函数指针: int add(int a,int b) { return a+b; } typedef int (*f ...
- javascript学习笔记 - 引用类型 Function
五 Function类型 每个函数都时Function类型的实例.函数也是对象. 声明函数: function func_name () {} //javascript解析器会在程序执行时率先读取函数 ...
- tensorflow学习笔记——自编码器及多层感知器
1,自编码器简介 传统机器学习任务很大程度上依赖于好的特征工程,比如对数值型,日期时间型,种类型等特征的提取.特征工程往往是非常耗时耗力的,在图像,语音和视频中提取到有效的特征就更难了,工程师必须在这 ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
随机推荐
- Shell排序——软考(五)
希尔排序是一种插入排序,是对直接插入排序的一种改进,该算法出自于D.L.Shell,因此得名为希尔.Shell排序又名缩小增量排序. 思想 假设初始序列为n个元素,先取一个小于n的整数d1作 ...
- Vue 组件生命周期钩子
Vue 组件生命周期钩子 # 1)一个组件从创建到销毁的整个过程,就称之为组件的生命周期 # 2)在组件创建到销毁的过程中,会出现众多关键的时间节点, 如: 组件要创建了.组件创建完毕了.组件数据渲染 ...
- python的拷贝方式以及深拷贝,浅拷贝详解
python的拷贝方法有:切片方法, 工厂方法, 深拷贝方法, 浅拷贝方法等. 几种方法都可以实现拷贝操作, 具体区别在于两点:1.代码写法不同. 2.内存地址引用不同 代码演示: import co ...
- 织梦个人空间中调用ip,会员类型,邮箱,金币,会员积分
织梦个人空间中调用.用户昵称,最后登录,会员等级 ,会员头衔,会员积分,空间访问,邮箱地址 ,金币数量,会员组的有效期天数 ,升级会员组的时间 ,用户的等级,用户的性别 ,会员的类型,ip 第一步确定 ...
- Kubernetes 学习16 RBAC
一.概述 1.前面讲过,kubernetes的授权也是基于插件来实现而且用户访问时某一次操作经由某一授权插件检查能通过后就不再经由其它插件检查.然后由准入控制插件再做进一步后续的准入控制检查.那么在他 ...
- C void的指针 强制类型转换(int*)p 把变量指针p强制转换成指向int类型的指针
#include <stdio.h> int main(void){ void *p; int a = 14322; char c ='A'; p = &a; //p = & ...
- Python学习之--列表
一.列表表示: 用方括号([] )来表示列表,并用逗号来分隔其中的元素,索引从0开始,如下 二.修改元素 三.添加元素: 1. append 2. insert 四. 删除元素: 1. del 2. ...
- 贴一段Matlab代码
% reduce leading zeros with rx ind3= find(rx~=0, 1, 'first'); if (isempty(ind3)) rx= gf(0, m, f0); e ...
- node.js Error: connect EMFILE 或者 getaddrinfo ENOTFOUND
Error: getaddrinfo ENOTFOUND] code: 'ENOTFOUND', errno: 'ENOTFOUND', syscall: 'getaddrinfo' Error: c ...
- Leetcode84. 柱状图中最大的矩形(单调栈)
84. 柱状图中最大的矩形 前置 单调栈 做法 连续区间组成的矩形,是看最短的那一块,求出每一块左边第一个小于其高度的位置,右边也同理,此块作为最短限制.需要两次单调栈 单调栈维护递增区间,每次不满足 ...