std::function & std::bind

函数指针简介

函数指针指向某种特定类型,函数的类型由其参数及返回类型共同决定,与函数名无关 。

int callWithMax(int a, int b)//函数定义

 这个函数的返回值是int,传入的两个参数也是int,所以这个函数的类型就是 int(int, int)类型,我们可以声明一个指向该函数的函数指针,声明如下:

int (*p)(int, int)//此时还未初始化

 这样的话这个函数指针就可以指向所有的int(int, int)类型的函数,我们让它指向callWithMax函数。

p = callWithMax;//等同于p = &callWithMax;

这样的话p就可以当作callWithMax函数用了。

源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

int (*p)(int, int);

int main(){
	p = &callWithMax;
	std::cout << p(1,2);
	return 0; 
}

输出 :

函数指针在c++11中的声明

1. typedef与decltype组合定义函数类型

按如下声明的话,pf就是一个函数类型,它和callWithMax类型相同。decltype()返回传入参数的数据类型。

typedef decltype(callWithMax) pf;

 源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

typedef decltype(callWithMax) pf;
int main(){
	pf* max;
	max = callWithMax;
	std::cout << max(1,2);
	return 0; 
}

输出:

你也可以直接使用如下直接声明函数指针

typedef decltype(callWithMax)* pf;

这样使用的话直接使用以下声明即可:

 

pf max;
max = callWithMax;

2.使用auto自动匹配函数类型

auto可以直接判断数据类型,因此这种写法最简单

	auto max = callWithMax;

源码:

#include<iostream>

int callWithMax(int a, int b){
	return a > b ? a : b;
}

int main(){
	auto max = callWithMax;
	std::cout << max(1,2);
	return 0; 
}

输出:

 

std::function 

 1.可调用对象

定义:

  • 是一个函数指针;
  • 是一个具有operator()成员函数的类的对象;
  • 可被转换成函数指针的类对象;
  • 一个类成员函数指针;

我们可以看以下三种写法:

int Max(int a, int b){return a > b ? a : b;}//普通函数
auto Max_lambda = [](int a, int b){return a > b ? a : b;}//lambda表达式
//仿函数
class Max_class{
public:
    int operator()(int a, int b){
        return a > b ? a : b;
    }
}

这三种写法都是同一个调用对象类型

int(int, int)

 而std::function就可以保存这个类型

std::function<int(int, int)> m1 = Max;
std::function<int(int, int)> m2 = Max_lambda;
std::function<int(int, int)> m3 = Max_class();

定义格式:std::function<函数类型>。 

std::function 是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。

std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。

std::bind

std::bind可以看作为是一个函数适配器,它接收一个可调用对象和它的参数,将其绑定为一个新的参数列表的可调用对象。

  • 将可调用对象和其参数绑定成一个仿函数;
  • 只绑定部分参数,减少可调用对象传入的参数。

对函数使用std::bind 

源码1:

#include<iostream>
/* 引入bind的头文件 */
#include <functional>
/* _1 下标的命名空间 */
using namespace std::placeholders;
double m_div(double a, double b){
	return a / b;
}
int main(){
    /* 给m_div绑定两个参数,第一个参数是函数名,第二个参数是_1也就是一个记号,以后传入的参数将代替这个位置(m_div的第一个参数) ,第三个参数是m_div的第二个参数*/
	auto half = std::bind(m_div,_1,2);
	std::cout << half(10);
	return 0; 
}

输出:

 

上述“auto half = std::bind(m_div,_1,2);”相当与声明了一个新的函数half,它的实现如下:

double m_div(double a/*, double b = 2*/){
	return a / b;
    //return a / 2;
}

源码2:

#include<iostream>
#include <functional>
double m_div(double a, double b){
	return a / b;
}
using namespace std::placeholders;
int main(){
	auto div_ = std::bind(m_div,_1,_2);//标记两个参数
	std::cout << div_(10, 5);
	return 0; 
}

输出:

 

对成员函数使用std::bind

源码:

#include<iostream>
#include <functional>
class Div{
	public:
		double m_div(double a, double b){
			return a / b;
		}
};
using namespace std::placeholders;
int main(){
	Div d;
    //第一个参数必须是&类名::函数名,第二个参数是类的地址,然后是参数列表下标 
	auto helf = std::bind(&Div::m_div, &d,_1,_2);
	std::cout << helf(10, 5);
	return 0; 
}

输出:

 

绑定一个引用参数

默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数希望以引用的方式传递,或是要绑定参数的类型无法拷贝。(以下代码引用自博客:https://www.jianshu.com/p/f191e88dcc80)

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std::placeholders;
using namespace std;

ostream & print(ostream &os, const string& s, char c)
{
    os << s << c;
    return os;
}

int main()
{
    vector<string> words{"helo", "world", "this", "is", "C++11"};
    ostringstream os;
    char c = ' ';
    for_each(words.begin(), words.end(), 
                   [&os, c](const string & s){os << s << c;} );
    cout << os.str() << endl;

    ostringstream os1;
    // ostream不能拷贝,若希望传递给bind一个对象,
    // 而不拷贝它,就必须使用标准库提供的ref函数
    for_each(words.begin(), words.end(),
                   bind(print, ref(os1), _1, c));
    cout << os1.str() << endl;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值