C++11中引入的bind绑定器和函数对象
知识点
- C++ STL中的绑定器
-
bind1st:operator()的第一个形参变量绑定成一个确定的值
-
bind2nd:operator()的第二个形参变量绑定成一个确定的值
-
目前使用bind
-
C++11从Boost库中引入了bind绑定器和function函数对象机制
-
lambda表达式,底层依赖函数对象的机制实现
应用实例:
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
template<class Container>
void showContainer(Container &con){
auto it = con.begin();
for(; it != con.end(); ++it){
cout << *it <<" ";
}
cout << endl;
}
int main(int argc, const char * argv[]) {
vector<int> vec;
srand(time(nullptr));
for(int i=0; i<20; ++i){
vec.push_back( rand() % 100 + 1);
}
showContainer(vec);
sort(vec.begin(), vec.end());//默认是<
showContainer(vec);
//greater二元函数对象
sort(vec.begin(), vec.end(), greater<int>());//>
showContainer(vec);
/*
把70按顺序插入到vec容器中,找第一个小于70的数字
operator()(const T &val)
greater a > b
less a < b
绑定器+二元函数对象 =》一元函数对象
bind1st: + greater bool operator()(70, const _Ty& _Right)
bind2nd: + less bool operator()(const _Ty& _Left, 70)
bind: placeholders::_1是占位符
*/
auto it1 = find_if(vec.begin(), vec.end(), bind(greater<int>(), 70, placeholders::_1));
if( it1 != vec.end()){
vec.insert(it1, 70);
}
showContainer(vec);
return 0;
-
bind绑定器返回的结果还是一个函数对象
-
bind是函数模板,可以自动推演模板类型参数
-
bind只能在语句中,出了语句不能使用
-
bind可以使用参数占位符placeholders::_1
void hello(string str){
cout << str << endl;
}
int sum(int a, int b){
return a+b;
}
int main(){
bind(hello, "hello bind!")();//hello bind!
bind(hello, placeholders::_1)("hello bind!");//hello bind!
cout << bind(sum, 10, 20)() << endl;//30
return 0;
}
function函数对象类型的应用
-
绑定器、函数对象、lambda表达式,他们只能使用在一条语句中,作用:保留这三类的类型
-
用函数类型实例化function
-
function调用operator()函数的时候,需要根据函数类型传入相应的参数
void func1() {cout << "hello weiwei" << endl;}
void func2(string str){ //void(*pFUNC)(string)
cout << str << endl;
}
int add(int a, int b){return a+b;}
class Test{
public://成员函数必须依赖对象,void(Test::*pFUNC)(string)
void func3(string str) {cout << str << endl;}
};
int main(){
//从function类模板定义template<class _Fty>要用一个函数类型实例化function
function<void()> FUNC1 = func1;
FUNC1();//func1.operator()
function<void(string)> FUNC2 = func2;
FUNC2("func2(string str)");//func2.opeartor()(string str)
function<int(int, int)> FUNC3 = add;
cout << FUNC3(3, 5) << endl;
//operator()
function<int(int, int)> FUNC4 = [](int a, int b)->int {return a+b;};
cout << FUNC4(30, 50) << endl;
//调用类成员函数
function<void(Test*, string)> FUNC5 = &Test::func3;
FUNC5(&Test(), "call Test::func3");
return 0;
}
- 菜单设计案例
void choiceNew() {cout << "New" << endl;}
void choiceOpen() {cout << "Open" << endl;}
void choiceSave() {cout << "Save" << endl;}
void choiceClose() {cout << "Close" << endl;}
int main(){
int choice = 0;
map<int, function<void()> > choiceMap;
choiceMap.insert(make_pair(1, choiceNew));
choiceMap.insert(make_pair(2, choiceOpen));
choiceMap.insert(make_pair(3, choiceSave));
choiceMap.insert(make_pair(4, choiceClose));
for(;;){
cout << "***************" << endl;
cout << "1.New" << endl;
cout << "2.Open" << endl;
cout << "3.Save" << endl;
cout << "4.Close" << endl;
cout << "***************" << endl;
cout << "请选择:" << endl;
cin >> choice;
auto mit = choiceMap.find(choice);
if(mit == choiceMap.end()){
cout << "输入无效" << endl;
break;
}
else{
mit->second();
}
}
return 0;
}
模板的完全特例化和部分特例化
- 引入
template<typename T>
bool compare(T a, T b){
cout << "template compare" << endl;
return a > b;
}
template<>
bool compare<const char*>(const char *a, const char *b){
cout << "compare<const char*>" << endl;
return strcmp(a, b) > 0;
}
int main(){
compare(10, 20);
compare("aaa", "bbb");//T const char*
return 0;
}
- 完全特例化和部分特例化示例
template<typename T>
class Test{
public:
Test(){cout << "call Test template" << endl;}
};
//对char *类型提供的完全特例化版本#1
template<>//特例化语法
class Test<char *>{
public:
Test(){cout << "call Test<char *> template" << endl;}
};
//针对指针类型提供的部分特例化版本#2
template<typename Ty>
class Test<Ty *>{
public:
Test(){cout << "call Test<Ty *> template" << endl;}
};
//针对函数指针(返回值,有两个形参变量)提供的部分特例化版本
template<typename R, typename A1, typename A2>
class Test<R(*)(A1, A2)>{
public:
Test(){cout << "call Test<R(*)(A1, A2) template" << endl;}
};
//针对函数类型提供的部分特例化版本
template<typename R, typename A1, typename A2>
class Test<R(A1, A2)>{
public:
Test(){ cout << "call Test<R(A1, A2) template" << endl;}
};
int main(){
Test<int> test1;//call Test template
Test<char*> test2;//call Test<char *> template
Test<int*> test3;//call Test<Ty *> template
Test<int(*)(int, int)> test4;//call Test<R(*)(A1, A2) template
Test<int(int, int)> test5;//call Test<R(A1, A2) template
return 0;
}
模板的实参推演
-
概念:从函数实参来确定模板实参的过程。在模板实参推演过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配
-
示例
template <typename T>//T包含了所有大的类型
void func1(T a){
cout << typeid(T).name() << endl;
}
template <typename R, typename A1, typename A2>
void func2( R (*a)(A1, A2) ){
cout << typeid(R).name() << endl;
cout << typeid(A1).name() << endl;
cout << typeid(A2).name() << endl;
};
template <typename R, typename T, typename A1, typename A2>
void func3( R (T::*a)(A1, A2)){
cout << typeid(R).name() << endl;
cout << typeid(T).name() << endl;
cout << typeid(A1).name() << endl;
cout << typeid(A2).name() << endl;
}
int add(int a, int b){return a+b;}
class Test{
public:
int add(int a, int b){return a+b;}
};
int main(){
func1(10);//int
func1("aaa");//char const *
func1(add);//int (__cdecl*)(int,int)
func2(add);//int int int
func1(&Test::add);//int (__thiscall Test::*)(int,int)
func3(&Test::add);//int class Test int int
return 0;
}
function函数对象实现的原理
template <typename R, typename... A>
class myFunction<R(A...)>{
public:
//using pFUNC = R(*)(A);
typedef R(*pFUNC)(A...);
myFunction(pFUNC func) : _pfunc(func){}
R operator()(A... arg){
return _pfunc(arg...);
}
private:
pFUNC _pfunc;
};
void func1(string str) { cout << str << endl;}
int add(int a, int b) { return a+b;}
int main(){
myFunction<void(string)> FUNC1(func1);
FUNC1("weiwei");
myFunction<int(int, int)> FUNC2(add);
cout << FUNC2(10, 20) << endl;
return 0;
}
bind和function应用
- 线程池应用
lambda表达式
-
函数对象的升级版
-
函数对象的缺点:使用在泛型算法参数传递,比较和自定义操作
-
如果表达式的返回值不需要,可以省略"->返回值"
-
语法:
[捕获外部变量](形参列表)->返回值{操作代码};
[]不捕获任何外部变量
[=]以传值的方式捕获外部的所有变量
[&]以引用的方式捕获外部的所有变量
[this]捕获外部的this指针
[=, &a]以传值的方式捕获外部所有变量,但是a变量以引用的方式捕获
[a, b]以传值的方式捕获外部变量a和b
[a, &b]a以传值的方式捕获,b以引用的方式捕获
int main(){
auto func1 = []()->void {cout << "weiwei" << endl;};
func1();
auto func2 = [](int a, int b)->int {return a + b;};
cout << func2(3, 10) << endl;
/*
int a = 10;
int b = 20;
auto func3 = [=](){//不能在非可变 lambda 中修改按值捕获
int tmp = a;
a = b;
b = tmp;
};
*/
int a = 10;
int b = 20;
auto func3 = [=]() mutable {
int tmp = a;
a = b;
b = tmp;
};
int a = 10;
int b = 20;
auto func4 = [&](){//不需要mutable
int tmp = a;
a = b;
b = tmp;
};
func4();
cout << "a:" << a << "b:" << b << endl;//20, 10
return 0;
}
- lambda表达式应用
int main(){
vector<int> vec;
for(int i = 0; i < 20; ++i){
vec.push_back(rand()%100 + 1);
}
sort(vec.begin(), vec.end(), [](int a, int b)->bool{ return a > b;});
for(int val : vec){
cout << val << " ";
}
cout << endl;
//将65按序插入到vec中
auto it = find_if(vec.begin(), vec.end(), [](int a)->bool{ return a < 65;});
vec.insert(it, 65);
for(int val : vec){
cout << val << " ";
}
cout << endl;
for_each(vec.begin(), vec.end(), [](int a){
if( a % 2 == 0){
cout << a << " ";
}
});
cout << endl;
system("pause");
return 0;
return 0;
}
-
lambda表达式只能使用在语句中,如何跨语句调用之前定义好的表达式,用什么类型来表示lambda表达式
- lambda表达式是函数对象,用function类型
int main(){
map<int, function<int(int, int)>> myMap;
myMap[1] = [](int a, int b)->int {return a + b;};
myMap[2] = [](int a, int b)->int {return a - b;};
myMap[3] = [](int a, int b)->int {return a * b;};
myMap[4] = [](int a, int b)->int {return a / b;};
cout << "2+3 = " << myMap[1](2, 3) << endl;
cout << "2-3 = " << myMap[2](2, 3) << endl;
cout << "2*3 = " << myMap[3](2, 3) << endl;
cout << "2/3 = " << myMap[4](2, 3) << endl;
return 0;
}
- 智能指针自定义删除器
int main(){
unique_ptr<FILE, function<void(FILE*)>>
pfile(fopen("data.txt", "w"), [](FILE *pf){fclose(pf);});
return 0;
}
- 优先队列
class Test{
public:
Test(int data1 = 10, int data2 = 20) : ma(data1), mb(data2){}
/*灵活性差
bool operator<(const Test &that) const { return this->ma < that.ma;}
bool operator>(const Test &that) const { return this->ma > that.ma;}
*/
int ma;
int mb;
};
int main(){
//priority_queue<Test> queue;
typedef function<bool(Test&, Test&)> FUNC;
priority_queue<Test, vector<Test>, FUNC>
LargeHeap([](Test &t1, Test &t2)->bool
{
return t1.ma > t2.ma;
});
LargeHeap.push(Test(10, 20));
LargeHeap.push(Test(15, 20));
LargeHeap.push(Test(10, 15));
return 0;
}