C++11中bind綁定器和function函數(shù)對(duì)象介紹
一. bind1st和bind2nd
1.C++ STL中的綁定器
- bind1st:operator()的第一個(gè)形參變量綁定成一個(gè)確定的值
- bind2nd:operator()的第二個(gè)形參變量綁定成一個(gè)確定的值
C++11從Boost庫(kù)中引入了bind綁定器和function函數(shù)對(duì)象機(jī)制
bind可用于給多元函數(shù)降元:Bind + 二元函數(shù)對(duì)象 = 一元函數(shù)對(duì)象
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>//泛型算法
#include<ctime>
using namespace std;
template<typename Container>
void showContainer(Container& con)
{
//typename Container::iterator it=con.begin();
auto it = con.begin();
for (; it != con.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
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());//默認(rèn)從小到大排序
showContainer(vec);
//greater需要二元函數(shù)對(duì)象
sort(vec.begin(), vec.end(), greater<int>());//從大到小排序
showContainer(vec);
/*
把70按順序插入到vec容器中 ->找第一個(gè)小于70的數(shù)字
operator()(const T &val)
greater a>b
less a<b
綁定器+二元函數(shù)對(duì)象=》一元函數(shù)對(duì)象
bind1st:+greater bool operator()(70,const_Ty&_Right)
bind2nd:+less bool operator()(const_Ty &_Left,70)
*/
auto it1 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70));
if (it1 != vec.end())
{
vec.insert(it1, 70);
}
showContainer(vec);
return 0;
}2.bind1st和bind2nd的底層原理實(shí)現(xiàn)
綁定器本身是一個(gè)函數(shù)對(duì)象
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
using namespace std;
template<typename Container>
void showContainer(Container& con)
{
auto it = con.begin();
for (; it != con.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}
//遍歷兩個(gè)迭代器之間的元素,如果滿足函數(shù)對(duì)象的運(yùn)算,就返回當(dāng)前的迭代器,如果都不滿足就返回end
template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare comp)
{
//這里傳入的comp是封裝好的一元函數(shù)對(duì)象
for (; first != last; ++first)
{
if (comp(*first))//獲取容器的一個(gè)元素
{
return first;
}
}
return last;
}
template<typename Compare,typename T>
class _mybind1st//綁定器是函數(shù)對(duì)象的一個(gè)應(yīng)用
{
public:
//這里傳入的comp是二元函數(shù)對(duì)象
_mybind1st(Compare comp,T val)
:_comp(comp),_val(val){}
//通過重載operator()把二元函數(shù)對(duì)象封裝為一元函數(shù)對(duì)象
bool operator()(const T& second)
{
return _comp(_val, second);
}
private:
Compare _comp;
T _val;
};
template<typename Compare,typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T& val)
{
//直接使用函數(shù)模板,好處是可以進(jìn)行類型的推演
//這里傳入的comp是一個(gè)二元函數(shù)對(duì)象
//通過二元函數(shù)對(duì)象構(gòu)造一元函數(shù)對(duì)象
//綁定器本身是一個(gè)函數(shù)對(duì)象,也就是重載了operator()
return _mybind1st<Compare, T>(comp, val);
}
int main()
{
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());//默認(rèn)從小到大排序
showContainer(vec);
//greater需要二元函數(shù)對(duì)象
sort(vec.begin(), vec.end(), greater<int>());//從大到小排序
showContainer(vec);
auto it1 = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70));
if (it1 != vec.end())
{
vec.insert(it1, 70);
}
showContainer(vec);
return 0;
}二. 模板的完全特例化和非完全特例化
有完全特例化優(yōu)先匹配完全特例化,有部分特例化就匹配部分特例化,沒有的話就從原模板自己實(shí)例化
#include<iostream>
using namespace std;
template<typename T>
class Vector
{
public:
Vector() { cout << "call Vector template init" << endl; }
};
//對(duì)char*類型提供完全特例化版本
template<>
class Vector<char*>
{
public:
Vector() { cout << "call Vector<char*> init" << endl; }
};
//對(duì)指針類型提供的部分特例化版本(部分:只知道是個(gè)指針,但是指針的類型是什么不知道)
template<typename Ty>
class Vector<Ty*>
{
public:
Vector() { cout << "call Vector<Ty*> init" << endl; }
};
//指針函數(shù)指針(有返回值,有兩個(gè)形參變量)提供的部分特例化
template<typename R,typename A1,typename A2>
class Vector<R(*)(A1, A2)>
{
public:
Vector() { cout << "call Vector<R(*)(A1,A2)> init" << endl; }
};
//針對(duì)函數(shù)(有一個(gè)返回值,有兩個(gè)形參變量)類型提供的部分特例化
template<typename R, typename A1, typename A2>
class Vector<R(A1, A2)>
{
public:
Vector() { cout << "call Vector<R(A1,A2)> init" << endl; }
};
int sum(int a, int b) { return a + b; }
int main()
{
Vector<int> vec1;
Vector<char*> vec2;
Vector<int*> vec3;
Vector<int(*)(int, int)> vec4;
Vector<int(int, int)> vec5;
//注意區(qū)分函數(shù)類型和函數(shù)指針類型
typedef int(*PFUNC1)(int, int);
PFUNC1 pfunc1 = sum;
cout << pfunc1(10, 20) << endl;
typedef int PFUNC2(int, int);
PFUNC2* pfunc2 = sum;
cout << (*pfunc2)(10, 20) << endl;
return 0;
}
#include<iostream>
#include<typeinfo>
using namespace std;
//T包含了所有大的類型
template<typename T>
void func(T a)
{
cout << typeid(T).name() << endl;
}
int sum(int a, int b) { return a + b; }
//把所有形參類型都取出來
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;
}
class Test
{
public:
int sum(int a, int b) { return a + b; }
};
int main()
{
//func(10);//int
//func("aaa");//const char *
func(sum);
func2(sum);
func3(&Test::sum);
return 0;
}
三. function函數(shù)對(duì)象
綁定器,函數(shù)對(duì)象,lambda表達(dá)式本質(zhì)上都是函數(shù)對(duì)象,只能使用在一條語(yǔ)句中,但是如果想要在多條語(yǔ)句中使用,就需要function
使用function函數(shù)需要注意:
- 用函數(shù)類型實(shí)例化function;
- 通過function調(diào)用
operator()函數(shù)的時(shí)候,需要根據(jù)函數(shù)類型傳入相應(yīng)的參數(shù)。
#include<iostream>
#include<functional>
using namespace std;
void hello1()
{
cout << "hello world!" << endl;
}
void hello2(string str)
{
cout << str << endl;
}
int sum(int a, int b)
{
return a + b;
}
int main()
{
//從function的模板定義處,看到希望用一個(gè)函數(shù)類型實(shí)例化function
function<void()> func1 = hello1;
func1();//func1.operator() => hello1()
function<void(string)> func2 = hello2;
func2("hello hello2!");
function<int(int, int)> func3 = sum;
cout << func3(2, 3) << endl;
function<int(int, int)> func4 = [](int a, int b)->int {return a + b; };
cout << func4(3, 4) << endl;
return 0;
}
function不僅可以留下普通全局函數(shù)的類型,對(duì)于類的成員方法也可以進(jìn)行類型保留:
#include<iostream>
#include<functional>
using namespace std;
class Test
{
public://必須依賴一個(gè)對(duì)象void(Test::*pfunc)(string)
void hello(string str) { cout << str << endl; }
};
int main()
{
//成員方法一經(jīng)編譯都會(huì)多一個(gè)當(dāng)前類型的this指針
function<void (Test*, string)> func = &Test::hello;
Test t;
//對(duì)于成員方法的調(diào)用需要依賴一個(gè)成員對(duì)象
func(&t, "call Test::hello!");
return 0;
}
function的特點(diǎn):可以把所有函數(shù)、綁定器、函數(shù)對(duì)象和lambda表達(dá)式的類型保留起來,在其他地方都可以使用。否則綁定器、lambda表達(dá)式就只能使用在語(yǔ)句中。
#include<iostream>
#include<functional>
#include<map>
using namespace std;
void doShowAllBooks(){ cout << "查看所有書籍信息" << endl; }
void doBorrow() { cout << "借書" << endl; }
void doBack() { cout << "還書" << endl; }
void doQueryBooks() { cout << "查詢書籍" << endl; }
void doLoginOut() { cout << "注銷" << endl; }
int main()
{
int choice = 0;
//使用function函數(shù)對(duì)象完成
map<int, function<void()>> actionMap;
actionMap.insert({ 1,doShowAllBooks });
actionMap.insert({ 2,doBorrow });
actionMap.insert({ 3,doBack });
actionMap.insert({ 4,doQueryBooks });
actionMap.insert({ 5,doLoginOut });
for (;;)
{
cout << "------------------" << endl;
cout << "1.查看所有書籍信息" << endl;
cout << "2.借書" << endl;
cout << "3.還書" << endl;
cout << "4.查詢書籍" << endl;
cout << "5.注銷" << endl;
cout << "------------------" << endl;
cout << "請(qǐng)選擇:";
cin >> choice;
auto it = actionMap.find(choice);
if (it == actionMap.end())
{
cout << "輸入數(shù)字無效,重新選擇" << endl;
}
else
{
it->second();
}
//不好,因?yàn)檫@塊代碼無法閉合,無法做到“開-閉”原則,也就是說這塊代碼隨著需求的更改需要一直改,永遠(yuǎn)也閉合不了,避免不了要產(chǎn)生很多問題
/*
switch(choice)
{
case 1:break;
case 2:break;
case 3:break;
case 4:break;
case 5:break;
default:break;
}
*/
}
return 0;
}function的實(shí)現(xiàn)原理:
#include<iostream>
#include<functional>
using namespace std;
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
template<typename Fty>
class myfunction{};
/*
template<typename R,typename A1>
class myfunction<R(A1)>
{
public:
//typedef R(*PFUNC)(A1);
using PFUNC = R(*)(A1);
myfunction(PFUNC pfunc):_pfunc(pfunc){}
R operator()(A1 arg)
{
return _pfunc(arg);
}
private:
PFUNC _pfunc;
};
template<typename R, typename A1,typename A2>
class myfunction<R(A1,A2)>
{
public:
//typedef R(*PFUNC)(A1);
using PFUNC = R(*)(A1,A2);
myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
R operator()(A1 arg1,A2 arg2)
{
return _pfunc(arg1,arg2);
}
private:
PFUNC _pfunc;
};
*/
//...表示可變參,A表示的是一組1類型,個(gè)數(shù)任意
template<typename R, typename... A>
class myfunction<R(A...)>
{
public:
using PFUNC = R(*)(A...);
myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
R operator()(A... arg)
{
return _pfunc(arg...);
}
private:
PFUNC _pfunc;
};
int main()
{
myfunction<void(string)> func1(hello);
func1("hello world");
myfunction<int(int, int)> func2(sum);
cout << func2(10, 20) << endl;
return 0;
}四. bind和function實(shí)現(xiàn)線程池
#include<iostream>
#include<functional>
using namespace std;
using namespace placeholders;
//C++11 bind 綁定器=>返回的結(jié)果是一個(gè)函數(shù)對(duì)象
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
class Test
{
public:
int sum(int a, int b) { return a + b; }
};
int main()
{
//bind是函數(shù)模板,可以自動(dòng)推演模板類型參數(shù)
bind(hello, "Hello bind!")();
cout << bind(sum, 20, 30)() << endl;
cout << bind(&Test::sum, Test(), 20, 30)() << endl;
//function只接受一個(gè)類型,綁定器可以給相應(yīng)的函數(shù)綁定固定的參數(shù),綁定器只能使用在語(yǔ)句當(dāng)中
//參數(shù)占位符,綁定器出了語(yǔ)句,無法繼續(xù)使用
bind(hello, _1)("hello bind 2");
cout << bind(sum, _1, _2)(20, 30) << endl;
//此處把bind返回的綁定器binder就復(fù)用起來了
function<void(string)> func1 = bind(hello, _1);
func1("hello china!");
func1("hello shan xi!");
func1("hello da li!");
}#include<iostream>
#include<functional>
#include<thread>
#include<vector>
using namespace std;
using namespace placeholders;
//線程類
class Thread
{
public:
Thread(function<void(int)> func,int no):_func(func),_no(no){}
thread start()
{
thread t(_func,_no);
return t;
}
private:
function<void(int)> _func;
int _no;
};
//線程池類
class ThreadPool
{
public:
ThreadPool(){}
~ThreadPool()
{
//釋放thread對(duì)象占用的堆資源
for (int i = 0; i < _pool.size(); i++)
{
delete _pool[i];
}
}
//開啟線程池
void startPool(int size)
{
for (int i = 0; i < size; i++)
{
//不管是C++里面的thread還是Linux里面的pthread需要的線程函數(shù)都是一個(gè)C函數(shù),是不能夠使用成員方法的,因?yàn)樗荂的函數(shù)類型,不可能把成員方法的函數(shù)指針給一個(gè)C的函數(shù)指針,接收不了。所以就需要綁定,把runInThread所依賴的參數(shù)全部綁定
_pool.push_back(new Thread(bind(&ThreadPool::runInThread, this, _1),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;
//把runInThread這個(gè)成員方法充當(dāng)線程函數(shù)
void runInThread(int id)
{
cout << "call runInThread! id:" << id << endl;
}
};
int main()
{
ThreadPool pool;
pool.startPool(10);
return 0;
}五. lambda表達(dá)式
- 函數(shù)對(duì)象的應(yīng)用:使用在泛型算法參數(shù)傳遞、比較性質(zhì)、自定義操作、優(yōu)先級(jí)隊(duì)列和智能指針
- 函數(shù)對(duì)象的缺點(diǎn):需要先定義一個(gè)函數(shù)對(duì)象類型,但是類型定義完后可能只是用在了定義的地方,后面可能不會(huì)再用了,沒有必要為了需要一個(gè)函數(shù)對(duì)象定義一個(gè)類型,這個(gè)類型就永遠(yuǎn)在代碼當(dāng)中。
C++11函數(shù)對(duì)象的升級(jí)版 => lambda表達(dá)式:
- lambda表達(dá)式:底層依賴函數(shù)對(duì)象的機(jī)制實(shí)現(xiàn)的。
- lambda表達(dá)式語(yǔ)法:[捕獲外部變量](形參列表) ->返回值{操作代碼};
如果lambda表達(dá)式的返回值不需要,那么“->返回值”可以省略
[捕獲外部變量]
- [ ]:表示不捕獲任何外部變量
- [=]:以傳值的方式捕獲外部的所有變量
- [&]:以傳引用的方式捕獲外部的所有變量[this]:捕獲外部的this指針
- [=,&a]:以傳值的方式捕獲外部的所有變量,但是a變量以傳引用的方式捕獲
- [a,b]:以傳值的方式捕獲外部變量a和b
- [a,&b]:a以值傳遞捕獲,b以傳引用的方式捕獲
1.lambda表達(dá)式的實(shí)現(xiàn)原理
#include<iostream>
using namespace std;
template<typename T=void>
class TestLambda01
{
public:
void operator()()
{
cout << "hello world" << endl;
}
};
template<typename T = int>
class TestLambda02
{
public:
TestLambda02() {}
int operator()(int a, int b)
{
return a + b;
}
};
template<typename T = int>
class TestLambda03
{
public:
TestLambda03(int a,int b):ma(a),mb(b){}
void operator()()const
{
int tmp = ma;
ma = mb;
mb = tmp;
}
private:
mutable int ma;
mutable int mb;
};
class TestLambda04
{
public:
TestLambda04(int &a,int &b):ma(a),mb(b){}
void operator()()const
{
int tmp = ma;
ma = mb;
mb = tmp;
}
private:
int& ma;
int& mb;
};
int main()
{
auto func1 = []()->void {cout << "hello world" << endl; };
func1();
auto func2 = [](int a, int b)->int {return a + b; };
cout << func2(20, 30) << endl;
int a = 10;
int b = 20;
//按值傳遞a,b值未被改變
auto func3 = [a, b]()mutable
{
int tmp = a;
a = b;
b = tmp;
};
func3();
cout << "a:" << a << " b:" << b << endl;
//傳引用值a,b值被改變
auto func4 = [&]()
{
int tmp = a;
a = b;
b = tmp;
};
func4();
cout << "a:" << a << " b:" << b << endl;
cout << "--------------------" << endl;
TestLambda01<> t1;
t1();
TestLambda02<> t2;
cout << t2(20, 30) << endl;
TestLambda03<> t3(a,b);
t3();
cout << "a:" << a << " b:" << b << endl;
TestLambda04 t4(a,b);
t4();
cout << "a:" << a << " b:" << b << endl;
return 0;
}
mutable:成員變量本身也不是常量,只不過在常方法中this指針被修飾成const,在聲明成員變量前加mutable,可以在const方法中修改普通的成員變量
lambda表達(dá)式后面修飾mutable相當(dāng)于在它的所有成員變量添加一個(gè)mutable修飾。
2.lambda表達(dá)式的應(yīng)用實(shí)踐
lambda表達(dá)式應(yīng)用于泛型算法:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
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按序插入序列 要找一個(gè)小于65的數(shù)字
auto it = find_if(vec.begin(), vec.end(),
[](int a)->bool {return a < 65; });
if (it != vec.end())
{
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;
return 0;
}既然lambda表達(dá)式只能使用在語(yǔ)句中,如果想跨語(yǔ)句使用之前定義好的lambda表達(dá)式,采用function類型來表示函數(shù)對(duì)象的類型。
哈希表的應(yīng)用:
#include<iostream>
#include<vector>
#include<map>
#include<functional>
using namespace std;
int main()
{
//auto只能出現(xiàn)在根據(jù)右邊表達(dá)式推導(dǎo)左邊的類型,只能使用在函數(shù)的局部作用域的范圍之內(nèi)
//預(yù)先lambda表達(dá)式不知道需要先存儲(chǔ)lambda表達(dá)式類型
map<int, function<int(int, int)>> caculateMap;
caculateMap[1] = [](int a, int b)->int {return a + b; };
caculateMap[2] = [](int a, int b)->int {return a - b; };
caculateMap[3] = [](int a, int b)->int {return a * b; };
caculateMap[4] = [](int a, int b)->int {return a / b; };
cout << "請(qǐng)選擇";
int choice;
cin >> choice;
cout << caculateMap[choice](10, 15) << endl;
return 0;
}智能指針自定義刪除器:
#include<iostream>
#include<vector>
#include<functional>
using namespace std;
int main()
{
unique_ptr<FILE, function<void(FILE*)>>
ptr1(fopen("data.txt", "w"), [](FILE* pf) {fclose(pf); });
}
傳入函數(shù)對(duì)象使得容器元素按照指定方式排列:
#include<iostream>
#include<vector>
#include<functional>
#include <queue>
using namespace std;
class Data
{
public:
Data(int val1=10,int val2=10):ma(val1),mb(val2){}
int ma;
int mb;
};
int main()
{
//優(yōu)先級(jí)隊(duì)列
//priority_queue<Data> queue;
using FUNC = function<bool(Data&, Data&)>;
priority_queue<Data, vector<Data>, FUNC>
maxHeap([](Data& d1, Data& d2)->bool
{
return d1.mb > d2.mb;
});
maxHeap.push(Data(10, 20));
maxHeap.push(Data(15, 15));
maxHeap.push(Data(20, 10));
}到此這篇關(guān)于C++11中bind綁定器和function函數(shù)對(duì)象介紹的文章就介紹到這了,更多相關(guān)C++bind綁定器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言編程中從密碼文件獲取數(shù)據(jù)的函數(shù)總結(jié)
這篇文章主要介紹了C語(yǔ)言編程中從密碼文件獲取數(shù)據(jù)的函數(shù)總結(jié),包括getpw()函數(shù)和getpwnam()函數(shù)以及getpwuid()函數(shù),需要的朋友可以參考下2015-08-08
C++實(shí)現(xiàn)讀取圖片長(zhǎng)度和寬度
這篇文章主要介紹了C++實(shí)現(xiàn)讀取圖片長(zhǎng)度和寬度,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04
基于C語(yǔ)言實(shí)現(xiàn)猜數(shù)字游戲
這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
簡(jiǎn)單掌握C++編程中的while與do-while循環(huán)語(yǔ)句使用
這篇文章主要介紹了C++編程中的while與do-while循環(huán)語(yǔ)句使用,區(qū)別就是while是先判斷再執(zhí)行,而do-while是先執(zhí)行再判斷,需要的朋友可以參考下2016-01-01
解析wprintf 中使用%I64d格式化輸出LONGLONG的詳細(xì)介紹
本篇文章是對(duì)wprintf 中使用%I64d格式化輸出LONGLONG進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

