C++11(5)
目录
12。function包装器
用法
function的应用
13。bind绑定
bind的应用——计算利息
万众瞩目的C++11它又来了,本章将继续讲解C++11更新的内容,欢迎观看!!!
12。function包装器
function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。
用法
#include<iostream>
using namespace std;
#include<vector>
#include<functional>//仿函数也在这个头文件里面
//function包装器
//function包装器 也叫作适配器。
//C++中的function本质是一个类模板,也是一个包装器。
//使用function包装器时需要头文件#include<functional>
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator() (int a, int b)
{
return a + b;
}
};
class Plus
{
public:
static int plusi(int a, int b)//没有this指针
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
// 包装可调用对象
//任何可以调用的对象都可以包装,什么函数指针(函数名),仿函数,lambda,主要用于包装函数
function<int(int, int)> f1 = f;
cout << f1(4, 5) << endl;
//可以看到包装器的用法
//function<包装对象的返回值(包装对象的参数的类型)> 包装器对象 = 函数指针(函数名)或仿函数对象或lambda对象
// 包装静态成员函数(没有this指针)
function<int(int, int)> f2 = Plus::plusi;//可加可不加&
cout << f2(2, 3) << endl;
// 包装非静态成员函数(有this指针)
Plus pd;
function<double(Plus*, double, double)> f5 = &Plus::plusd;//成员函数有一个this指针所以需要多一个变量类型
cout << f5(&pd, 1.1, 2.2) << endl; //包装成员函数时必须加上&(语法规定)
//传匿名对象也可以,因为这里的this对于包装器的作用主要是为了找到这个成员函数在哪里,自然指针可以帮助找到,匿名对象也可以的,这里和类型就没有关系了
function<double(Plus, double, double)> f7 = &Plus::plusd;
cout << f7(Plus(), 1.1, 2.2) << endl;
// 包装仿函数
function<int(int, int)> f3 = Functor();
cout << f3(2, 3) << endl;
//包装lambda对象
function<int(int, int)> f4 = [](int a, int b) {return a + b; };
cout << f4(2, 3) << endl;
return 0;
}
//那这个function有什么实际价值呢
//当一个模板可以实例化出三个类型不同的对象时,由于对象类型不同我们不好处理
//这里的对象比如函数,仿函数,多个lambda对象,我们可以将他们用function
//封装起来,这样只需要保留一个function类型的对象就好处理了
//所以function<()> f也是有类型的
另外上面提到了包装器可以使被包装的类型统一,所以可以解决模板的效率低下,实例化多份的问题。
function的应用
既然上面说了,包装器可以解决模板效率低下的问题和实例化多份使得类型不一致的问题,既然类型不一致如果可以有一个统一的类型来装就可以解决这个问题了。这个在后面智能指针的实现需要特别使用function。
下面是实现逆波兰表达式的程序,我们可以使用lambda进行实现
https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/submissions/
13。bind绑定
std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可 调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而 言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M 可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺 序调整等操作。
//bind绑定
//std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可
//调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而
//言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M
//可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺
//序调整等操作。
//简单来说就是用来调整函数参数个数和位置的,主要是用来调整参数个数的因为位置没什么好调整的
using placeholders::_1;
using placeholders::_2;
int Sub(int a, int b)
{
return (a - b) * 10;
}
int SubX(int a, int b, int c)
{
return (a - b - c) * 10;
}
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
class Rate
{
public:
Rate(double rate) : _rate(rate)
{}
double operator()(double money, int year)
{
return money * _rate * year;
}
private:
double _rate;
};
int main()
{
auto it = bind(Sub, _1, _2);
// bind 本质返回的一个仿函数对象, 所以bind有返回值
// 调整参数顺序(不常用)
// _1代表第一个实参
// _2代表第二个实参
//...
//用法
//bind由于是一个函数模板,所以可以看成函数,这样它的第一个参数是所要bind的函数指针,接着的参数就是
//所要绑定的函数参数的第一个实参的位置的代号_1 ... 这些代号在placeholders这个类里面,所以需要使用代号时
//需要先声明一下(using一下)不然找不到
cout << it(2, 1) << endl;
auto its = bind(Sub, _2, _1);
cout << its(2, 1) << endl;
// 调整参数个数 (常用)
//由于bind返回的是新函数对象所以可以通过function再包装
auto sub1 = bind(Sub, 100, _1);
cout << sub1(2) << endl;
auto sub2 = bind(Sub, _1, 100);
cout << sub2(2) << endl;
//所以bind一般用于,绑死一些固定参数
// 分别绑死第123个参数
auto sub5 = bind(SubX, 100, _1, _2);
cout << sub5(5, 1) << endl;
auto sub6 = bind(SubX, _1, 100, _2);
cout << sub6(5, 1) << endl;
auto sub7 = bind(SubX, _1, _2, 100);
cout << sub7(5, 1) << endl;
//以上函数可以看成经过绑定后均剩下两个参数
//可以看到这边的实参的位置是指从没有被绑定的参数开始的,然后计算时会绕过被绑定的参数
//可以看成被bind绑定的参数就消失了,不算参数了,毕竟不需要自己传了
function<double(Plus, double, double)> f6 = &Plus::plusd;
Plus pd;
cout << f6(pd, 1.1, 1.1) << endl;
cout << f6(Plus(), 1.1, 1.1) << endl;
//每次这样写比较麻烦,我们可以使用先绑定第一个参数,然后用其返回的是函数对象的特点再进行function包装
function<double(double, double)> f7 = bind(&Plus::plusd, &pd, _1, _2);//&Plus::plusd,非静态成员函数必须&
cout << f7(1.1, 1.1) << endl;
return 0;
}
bind的应用——计算利息
int main()
{
//bind绑定lambda对象,无论是绑定什么对象,被bind绑定后,bind对象会执行被绑定的函数体的内容
auto func1 = [](double rate, double monty, int year)->double
{
double rat = monty;
for (int i = 0; i < year; i++)
{
rat += rat * rate;//算逐年累计的获利+本金
}
return rat - monty;//算出利息
};
function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);
function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);
function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10);
function<double(double)> func20_3_5 = bind(func1, 0.035, _1, 30);
//会发现比如算利息这种函数,是不是只需要传入本金就可以了,因为每次利率和年份是固定的
//所以可以使用绑定绑死,这样可以提高操作效率
cout << func3_1_5(1000000) << endl;
cout << func5_1_5(1000000) << endl;
cout << func10_2_5(1000000) << endl;
cout << func20_3_5(1000000) << endl;
return 0;
}