1. Function (函数模板:实现函数对象的函数类型的保存):
可以使用Function 实现对函数的封装为function对象,并且灵活调用;
解决了函数对象lambda表达式、bind绑定器只能限制在当前语句使用的局限;
1.1. 函数对象类型:
string Hello()
{
return "hello world";
}
int sum(int a, int b)
{
return a + b;
}
class Yab
{
public:
void Hello(string s)
{
cout<< s+s;
}
};
string H(string s)
{
return s;
}
//function:可以实现函数对象(:绑定器、函数对象、lambda表达式) 的类型保存,而不是只在单条语句才能执行
int main()
{
//function(函数模板) 用函数类型实例化
//1 用普通函数实例化function1
function<string()>function1 = Hello;
cout<<function1()<<endl;
function<int(int, int)>function2=sum;
cout << function2(11, 10)<<endl;
//2 用类的成员函数实例化function
//function<void(Yab*, string)>function3 = [](Yab* yab, string a)->void {
// cout << a + a;
//};
function<void(Yab*, string)>function3 = &Yab::Hello;
Yab y;
function3(&y, "hahahaha ");
//3 用lambda表达式实例化function
function<string(string, string)>function4 =
[](string s1, string s2)->string {
return s1 + s2;
};
cout << function4("lulu ", " fighting!");
return 0;
}
function总结:
- function对象需要函数类型((函数返回类型(函数参数类型))实例化
- function类对象被调用后,即调用operator()( )对象括号的重载函数,第二个括号内为函数参数,在函数内部调用被封装的函数,
- 调用对象function(),()内写入函数类型参数一致的参数
1.2. function可以优化项目目录的问题:
在跳转执行函数的选择中,我们最常使用的switch(),违背开闭原则,而利用function直接绑定函数,用map封装function与之匹配的选项,在添加删除时更加安全
//这是配置好的模板文件
#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>
#include<map>
using namespace std;
using namespace placeholders;
void Show()
{
cout << " 欢迎来到图书管理系统:\n";
cout << "**********************\n";
cout << " 1: 图书信息查询\n";
cout << " 2: 图书信息修改\n";
cout << " 3: 图书信息删除\n";
cout << " 4: 图书信息新增\n";
cout << " 5: 退出\n";
cout << "**********************\n";
}
void Showbook1()
{
cout << " 欢迎来到信息查询\n";
}
void Modefiybook2()
{
cout << " 欢迎来到信息修改\n";
}
void Deletehbook3()
{
cout << " 欢迎来到信息删除\n";
}
void Insertbook4()
{
cout << " 欢迎来到信息新增\n";
}
void Mapinsert(map<int, function<void()>>Hmap)
{
Hmap.insert({ 1, Showbook1 });
Hmap.insert({ 2, Modefiybook2 });
Hmap.insert({ 3, Deletehbook3 });
Hmap.insert({ 4, Insertbook4 });
}
int main()
{
Show();
map<int, function<void()>>Hmap;//插入function 对象到map结合中
Mapinsert(Hmap);
int i = 0;
//推荐方法1:
//while (1)
//{
// cin >> i;
// if (i == 5)
// break;
// auto it = Hmap.find( i);
// if ( it== Hmap.end())
// {
// cout << " 请输入有效选项";
// }
// else
// {
// it->second();
// }
//}
//方法2:
//违背了开闭原则,无异于维护修改
/*while (i != 5)
{
cin >> i;
switch(i)
{
case 1:
Showbook1();
break;
case 2:
Modefiybook2();
break;
case 3:
Deletehbook3();
break;
case 4:
Insertbook4();
break;
};
}*/
return 0;
}
2. function 的底层实现原理:
利用模板类实现函数对象,在小括号重载函数中调用功能函数
//!!!
template <typename FTY>
class myfunction{};
template<typename R,typename ...A>
class myfunction<R(A...)>
{
public:
using PFUNC = R * (A...);
myfunction(PFUNC _pfunc) :pfunc(_pfunc) {};
R operator()(A ...arg)
{
return func(arg...);
}
private:
PFUNC pfunc;
};
//!!!
void Hello()
{
cout << "hello world!";
}
double sum(float a, double b, float c, int d)
{
return a + b * c - d;
}
int main()
{
function<void()>fun = Hello;
fun();
//模板类中对于函数参数,改为可变参数的序列集合"A...arg",可包容各个函数的参数类型个数
function<double(float, double, float, int)>fun2 = sum;
cout<<fun2(1.22222222222,2.999999,3.22222,4.3333);
return 0;
}
2. Bind(绑定器函数模板:实现对函数的绑定):
2.1. bind1st,bind2nd:
C++ STL 绑定器,将二元函数(两个参数的函数)
- (bind1st)第一个参数 绑定为固定值,成为一元函数对象
- (bind2nd) 第二个参数 绑定为固定值,成为一元函数对象
sort(v.begin(), v.end(), greater<int>());
//降序:
//在第一个小于7的数据迭代器位置插入7
//less<>: a<b 绑定第二个迭代器,成为一元函数对象
// greater<>:a>b 绑定第一个迭代器:第一个小于七
//find_if :一元函数对象
auto it3 = find_if(v.begin(), v.end(), bind2nd(less<int>(), 7));
auto it3 = find_if(v.begin(), v.end(), bind1st(greater<int>(), 7));
2.1.1. 自己的封装 bind1st , find_if:
#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>
using namespace std;
template<typename Iterator, typename Compare>
Iterator myfind_if(Iterator first, Iterator last, Compare comp)
{
for (; first != last; first++)
{
if (comp(*first))
break;
}
return first;
}
template<typename Compare,typename T>
class _mybind1st
{
public:
_mybind1st(Compare comp, T val) :_comp(comp), _val(val) {};
bool operator()(const T& a)
{
return _comp(_val,a);
}
private:
Compare _comp;
T _val;
};
template<typename Compare, typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T val)
{
return _mybind1st<Compare, T>(comp, val);
}
template<typename Compare,typename T>
class _mybind2nd
{
private:
T _val;
Compare _comp;
public:
_mybind2nd(Compare comp, T val) :_comp(comp), _val(val) {};
bool operator()(const T& a)
{
return _comp(_val, a);
}
};
template<typename Compare,typename T>
_mybind2nd<Compare, T> mybind2nd(Compare comp, const T& val)
{
return _mybind2nd<Compare, T>(comp, val);
}
void Hello()
{
cout << "hello world!";
}
double sum(float a, double b, float c, int d)
{
return a + b * c - d;
}
int main()
{
vector<int>v;
for (int i = 0; i < 12; i++)
{
v.push_back(rand() % 11);
}
sort(v.begin(), v.end(), greater<int>());
//插入6 a>b
auto it = myfind_if(v.begin(), v.end(), mybind1st(greater<int>(), 6));
if (it != v.end())
v.insert(it,6);
//插入10 a<b
auto it2 = myfind_if(v.begin(), v.end(), mybind2nd(greater<int>(), 9));
if (it2 != v.end())
v.insert(it2, 9);
for (auto it : v)
{
cout << it << " ";
}
return 0;
}
2.1.2. bind 的应用举例:
//bind绑定器的参数占位符:placeholders
using namespace placeholders;
int sum(int a, int b)
{
return a + b;
}
void hello(string s)
{
cout << s;
}
class Ba
{
public:
int sum(int a, int b)
{
return a + b;
}
};
int main()
{
cout<<bind(sum,10, 20)() << endl;
bind(hello, placeholders::_1)("hello 2024");
cout<< endl;
cout << bind(&Ba::sum, Ba(), 30, 30)()<<endl;
return 0;
}
2.1.2.1. 结合function 则可以将bind器的函数结构保存,并不断复用
//bind()绑定器将函数对象的执行只局限与绑定的当前语句内,而结合function 则可以将bind器的函数结构保存,并不断复用
//bind绑定器的参数占位符:placeholders
using namespace placeholders;
function<void(string)>fun1 = bind(hello, _1);
function<int(int, int)>fun2 = bind(sum, _1, _2);
function<int(int, int)>fun3 = bind(&Ba::sum, Ba(), _1, _2);
fun1("hello ");
fun1("2024 and ");
fun1("2002 ");
cout << endl;
cout << fun2(1, 2) << " ";
cout << fun2(10, 20)<< " ";
cout << fun2(100, 200)<<endl;
cout << fun3(1, 2) << " ";
cout << fun3(10, 20) << " ";
cout << fun3(100, 200) << endl;
2.1.3. bind 结合function 实现线程池
#include <iostream>
#include <string>
#include<functional>//包含所有函数对象
#include<algorithm>//包含所有泛型算法
#include<vector>
#include<ctime>
#include<thread>
using namespace std;
//线程池:
class Thread
{
public:
Thread(function<void()>func) :_func(func) {};
thread start()
{
return thread(_func);
}
private:
function<void()>_func;
};
class Threadpool
{
public:
Threadpool() {};
~Threadpool() {
for (int i = 0; i < _pool.size(); i++)
{
delete _pool[i];
}
};
//开启线程池(size:线程池中的线程数量)
void startpool(int size)
{
for (int i = 0; i < size; i++)
{
_pool.push_back(new Thread(
bind(&Threadpool::runThread, this, i)));
}
for (int i = 0; i < size; i++)
{
_handler.push_back(_pool[i]->start());
}
for (thread& t : _handler)
{
t.join();
}
}
private:
vector<Thread*>_pool;
vector<thread>_handler;//句柄
//线程函数
void runThread(int id)
{
cout << "call runThread ! id: " << id << endl;
}
};
int main()
{
Threadpool pool;
pool.startpool(10);
return 0;
}
3. Lambda(构造函数对象):
在泛型算法、自定义函数比较、优先级队列中,对于函数对象的优化以及简化构建,避免代码中出现大量仅重载小括号的类
3.1.1. 格式:
[ 捕获外部变量 ] ( 参数列表 ) -> 函数返回值类型 {
实现代码...
};
3.1.1.1. 外部变量捕获方式:
[ ]:默认不捕获任何变量
[&] :引用 , [*] :指针 , [=] :值 , [this] : 捕获this指针对象
[=a,&b] : 值捕获a ,引用捕获 b ...
3.1.1.2. 注意:
- 若函数返回值类型为void,可以省略 ->及类型
- [=] ,值捕获的变量在第一次捕获入lambda表达式内以后,不再改变,即使函数外捕获变量的值改变,lambda表达式内的值依然为首次捕获
eg:
int a = 10, b = 20;
auto fun1=[=]() {cout << a + b<<endl;};
//lambda 表达式的值捕获,只保存第一次进入lambda表达式捕获的值,后面有修改也不会改变内部的值
fun1(); a = 20; fun1();
3.1.2. lambda的实现与应用
lambda表达式作为函数对象只限制在语句内使用,若想实现已经定义好的lambda类型,需要结合function<>(已经确定的lambda函数类型实例化),并在实例化对象的同时实现lambda函数,在之后则可以直接使用
3.1.2.1. 实现在优先级队列中的自定义比较函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<functional>
using namespace std;
class Data
{
private:
public:
int a1;
int b1;
Data(int a, int b) :a1(a), b1(b) {};
//方法一:不够灵活,在参数和比较方式增多时,在类中重载比较方式显得尤为笨重
//bool operator>(const Data& data)const { return a1 > data.a1; };
//bool operator<(const Data& data)const { return a1 < data.a1; };
void Show()const { cout << a1 << " " << b1 << endl; };
};
int main()
{
//priority_queue<Data>data;
//方法二:
using func = function<bool(Data&,Data&)> ;
using Pri_que=priority_queue<Data, vector<Data>, func>;
Pri_que data ([](Data& data1,Data& data2)->bool {
return data1.a1 > data2.a1;
});
for(int i=0;i<10;i++)
data.push(Data(10+i*5, 20));
while (!data.empty())
{
data.top().Show(); // 直接调用 Show 方法
data.pop(); // 不要忘记弹出元素,否则会导致无限循环
}
}
3.1.2.2. 实现智能文件指针的自定义删除器
//use _CRT_SECURE_NO_WARNINGS.See online help for details.Project5 D : \小徐同学\练习\Project5\lambda.cpp 60
using Ptr = unique_ptr<FILE, function<void(FILE*)>>;
Ptr p1(fopen("data.txt", "rb"), [](FILE* pf) {fclose(pf); });
//拥有自定义删除器的文件指针
3.1.2.3. 实现map 的调用方法:
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(rand() % 11);
cout << v[i]<<" ";
}
sort(v.begin(), v.end(), [](int c,int d)->bool {
return c<d;
});
cout << endl << endl;
map<int, function<int(int, int)>>map;
map[0] = [](int a, int b)->int {return a + b; };
map[1] = [](int a, int b)->int {return a - b; };
map[2] = [](int a, int b)->int {return a * b; };
map[3] = [](int a, int b)->int {return a / b; };
for(int i=0;i<4;i++)
cout << map[i](1, 2)<<endl;