<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
C++11從Boost庫中引入了bind繫結器和function函數物件機制
bind可用於給多元函數降元:Bind + 二元函數物件 = 一元函數物件
#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());//預設從小到大排序 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) */ auto it1 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70)); if (it1 != vec.end()) { vec.insert(it1, 70); } showContainer(vec); return 0; }
繫結器本身是一個函數物件
#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; } //遍歷兩個迭代器之間的元素,如果滿足函數物件的運算,就返回當前的迭代器,如果都不滿足就返回end template<typename Iterator,typename Compare> Iterator my_find_if(Iterator first, Iterator last, Compare comp) { //這裡傳入的comp是封裝好的一元函數物件 for (; first != last; ++first) { if (comp(*first))//獲取容器的一個元素 { return first; } } return last; } template<typename Compare,typename T> class _mybind1st//繫結器是函數物件的一個應用 { public: //這裡傳入的comp是二元函數物件 _mybind1st(Compare comp,T val) :_comp(comp),_val(val){} //通過過載operator()把二元函數物件封裝為一元函數物件 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) { //直接使用函數模板,好處是可以進行型別的推演 //這裡傳入的comp是一個二元函數物件 //通過二元函數物件構造一元函數物件 //繫結器本身是一個函數物件,也就是過載了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());//預設從小到大排序 showContainer(vec); //greater需要二元函數物件 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; }
有完全特例化優先匹配完全特例化,有部分特例化就匹配部分特例化,沒有的話就從原模板自己範例化
#include<iostream> using namespace std; template<typename T> class Vector { public: Vector() { cout << "call Vector template init" << endl; } }; //對char*型別提供完全特例化版本 template<> class Vector<char*> { public: Vector() { cout << "call Vector<char*> init" << endl; } }; //對指標型別提供的部分特例化版本(部分:只知道是個指標,但是指標的型別是什麼不知道) template<typename Ty> class Vector<Ty*> { public: Vector() { cout << "call Vector<Ty*> init" << endl; } }; //指標函數指標(有返回值,有兩個形參變數)提供的部分特例化 template<typename R,typename A1,typename A2> class Vector<R(*)(A1, A2)> { public: Vector() { cout << "call Vector<R(*)(A1,A2)> init" << endl; } }; //針對函數(有一個返回值,有兩個形參變數)型別提供的部分特例化 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; //注意區分函數型別和函數指標型別 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; }
繫結器,函數物件,lambda表示式本質上都是函數物件,只能使用在一條語句中,但是如果想要在多條語句中使用,就需要function
使用function函數需要注意:
operator()
函數的時候,需要根據函數型別傳入相應的引數。#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的模板定義處,看到希望用一個函數型別範例化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不僅可以留下普通全域性函數的型別,對於類的成員方法也可以進行型別保留:
#include<iostream> #include<functional> using namespace std; class Test { public://必須依賴一個物件void(Test::*pfunc)(string) void hello(string str) { cout << str << endl; } }; int main() { //成員方法一經編譯都會多一個當前型別的this指標 function<void (Test*, string)> func = &Test::hello; Test t; //對於成員方法的呼叫需要依賴一個成員物件 func(&t, "call Test::hello!"); return 0; }
function的特點:可以把所有函數、繫結器、函數物件和lambda表示式的型別保留起來,在其他地方都可以使用。否則繫結器、lambda表示式就只能使用在語句中。
#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函數物件完成 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 << "請選擇:"; cin >> choice; auto it = actionMap.find(choice); if (it == actionMap.end()) { cout << "輸入數位無效,重新選擇" << endl; } else { it->second(); } //不好,因為這塊程式碼無法閉合,無法做到「開-閉」原則,也就是說這塊程式碼隨著需求的更改需要一直改,永遠也閉合不了,避免不了要產生很多問題 /* switch(choice) { case 1:break; case 2:break; case 3:break; case 4:break; case 5:break; default:break; } */ } return 0; }
function的實現原理:
#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型別,個數任意 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; }
#include<iostream> #include<functional> using namespace std; using namespace placeholders; //C++11 bind 繫結器=>返回的結果是一個函數物件 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是函數模板,可以自動推演模板型別引數 bind(hello, "Hello bind!")(); cout << bind(sum, 20, 30)() << endl; cout << bind(&Test::sum, Test(), 20, 30)() << endl; //function只接受一個型別,繫結器可以給相應的函數繫結固定的引數,繫結器只能使用在語句當中 //引數預留位置,繫結器出了語句,無法繼續使用 bind(hello, _1)("hello bind 2"); cout << bind(sum, _1, _2)(20, 30) << endl; //此處把bind返回的繫結器binder就複用起來了 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物件佔用的堆資源 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需要的執行緒函數都是一個C函數,是不能夠使用成員方法的,因為它是C的函數型別,不可能把成員方法的函數指標給一個C的函數指標,接收不了。所以就需要繫結,把runInThread所依賴的引數全部繫結 _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這個成員方法充當執行緒函數 void runInThread(int id) { cout << "call runInThread! id:" << id << endl; } }; int main() { ThreadPool pool; pool.startPool(10); return 0; }
C++11函數物件的升級版 => lambda表示式:
如果lambda表示式的返回值不需要,那麼“->返回值”可以省略
[捕獲外部變數]
#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表示式後面修飾mutable相當於在它的所有成員變數新增一個mutable修飾。
lambda表示式應用於泛型演演算法:
#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按序插入序列 要找一個小於65的數位 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表示式只能使用在語句中,如果想跨語句使用之前定義好的lambda表示式,採用function型別來表示函數物件的型別。
雜湊表的應用:
#include<iostream> #include<vector> #include<map> #include<functional> using namespace std; int main() { //auto只能出現在根據右邊表示式推導左邊的型別,只能使用在函數的區域性作用域的範圍之內 //預先lambda表示式不知道需要先儲存lambda表示式型別 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 << "請選擇"; 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); }); }
傳入函數物件使得容器元素按照指定方式排列:
#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() { //優先順序佇列 //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)); }
到此這篇關於C++11中bind繫結器和function函數物件介紹的文章就介紹到這了,更多相關C++bind繫結器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45