STL之函數對象和謂詞

1.函數對象

重載函數調用操作符的類,其對象常稱為函數對象(function object),即它們是行為類似函數的對象。一個類對象,表現出一個函數的特征,就是通過“對象名+(參數列表)”的方式使用一個類對象,如果沒有上下文,完全可以把它看作一個函數對待。
這是通過重載類的operator()來實現的。
“在標準庫中,函數對象被廣泛地使用以獲得彈性”,標準庫中的很多算法都可以使用函數對象或者函數來作為自定的回調行為;

一元函數對象:函數參數1個;
二元函數對象:函數參數2個;

2.謂詞

一元謂詞: 函數參數1個,函數返回值是bool類型,可以作為一個判斷式

二元謂詞: 函數參數2個,函數返回值是bool類型

謂詞可以使一個仿函數,也可以是一個回調函數。

一元謂詞舉例如下:
1.判斷給出的string對象的長度是否小于6

bool GT6(const string &s)
{
return s.size() >= 6;
}

2.判斷給出的int是否在3到8之間

bool Compare( int i )
{
return ( i >= 3 && i <= 8 );
}

二元謂詞舉例如下:
1.比較兩個string對象,返回一個bool值,指出第一個string是否比第二個短

bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}

3.一元函數對象案例

//1普通類 重載 函數調用操作符
template <typename T>
void FuncShowElemt(T &t)  //普通函數 不能像 仿函數那樣記錄狀態
{cout << t << " ";
};void showChar(char &t)
{cout << t << " ";
}//函數模板 重載 函數調用操作符
template <typename T>
class ShowElemt
{
public:ShowElemt(){n = 0;}void operator()(T &t){n++;cout << t << " ";}void printCount(){cout << n << endl;}
public:int n;
};//1 函數對象 基本使用
void main11()
{int a = 100;FuncShowElemt<int>(a); //普通的函數調用ShowElemt<int> showElemt; //函數對象 showElemt(a); //函數對象調用 
}

4.一元謂詞案例

//1元謂詞 例子
template <typename T>
class Isdiv
{
public:Isdiv(const T &divisor) //{this->divisor = divisor;}bool operator()(T &t){return (t%divisor == 0);}
protected:
private:T divisor;
};void main13()
{vector<int> v2;for (int i=10; i<33; i++){v2.push_back(i);}vector<int>::iterator it;int a = 4;Isdiv<int> mydiv(a);// _InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred)   //返回的是迭代器it = find_if(v2.begin(), v2.end(), Isdiv<int>(4));if (it != v2.end()){cout << "第一個被4整除的數是:" << *it << endl;}
}

5.二元函數對象案例

template <typename T>
struct SumAdd
{T operator()(T &t1, T &t2){return t1 + t2;}
};template <typename T>
void printE(T &t)
{for (vector<int>::iterator it = t.begin(); it!=t.end(); it++ ){cout << *it << " ";}
}void printVector(vector<int> &v)
{for (vector<int>::iterator it = v.begin(); it!=v.end(); it++ ){cout << *it << " ";}
}void  main14()
{vector<int> v1, v2 ;vector<int> v3;v1.push_back(1);v1.push_back(2);v1.push_back(3);v2.push_back(4);v2.push_back(5);v2.push_back(6);v3.resize(10);//transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), SumAdd<int>());/*template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline_OutIt transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func)*/vector<int>::iterator it = transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), SumAdd<int>());cout << *it << endl;printE(v3); 
}

6.二元謂詞案例

void current(int &v)
{cout << v << " ";
}bool MyCompare(const int &a, const int &b)
{return a < b;
}
void main15()
{vector<int> v(10);for (int i=0; i<10; i++){v[i] = rand() % 100;}for_each(v.begin(), v.end(), current);printf("\n");sort(v.begin(), v.end(), MyCompare );printf("\n");for (int i=0; i<10; i++){printf("%d ", v[i]);}printf("\n");
}

7.綜合示例代碼

#include <iostream>
using namespace std;#include "string"
#include <vector>
#include <list>
#include "set"
#include <algorithm>
#include "functional"//函數對象 類重載了()
template <typename T>
class ShowElemt
{
public:ShowElemt(){n = 0;}void operator()(T &t){n ++;//printN();cout << t << " ";}void printN(){cout << "n:" << n << endl;}
protected:
private:int n;
};//函數模板  ==函數
template <typename T>
void FuncShowElemt(T &t)
{cout << t << endl;
}//普通函數
void FuncShowElemt2(int &t)
{cout << t << " ";
}//函數對象 定義 ;  函數對象和普通函數的異同 
//
void main01()
{int a = 10;ShowElemt<int> showElemt;showElemt(a); //函數對象的()的執行 很像一個函數 //仿函數FuncShowElemt<int>(a);FuncShowElemt2(a);
}//函數對象是屬于類對象,能突破函數的概念,能保持調用狀態信息
//函數對象的好處
// for_each算法中, 函數對象做函數參數
// for_each算法中, 函數對象當返回值
void main02()
{vector<int> v1;v1.push_back(1);v1.push_back(3);v1.push_back(5);for_each(v1.begin(), v1.end(), ShowElemt<int>()); //匿名函數對象 匿名仿函數cout << endl;for_each(v1.begin(), v1.end(), FuncShowElemt2); //通過回調函數  誰使用for_each 誰去填寫回調函數的入口地址ShowElemt<int> show1;//函數對象 做函數參數 /*template<class _InIt,class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func){   // perform function for each element_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Func);return (_For_each(_Unchecked(_First), _Unchecked(_Last), _Func));}*///1 for_each算法的 函數對象的傳遞 是元素值傳遞 ,不是引用傳遞for_each(v1.begin(), v1.end(), show1);show1.printN();cout << "通過for_each算法的返回值看調用的次數" << endl;show1 = for_each(v1.begin(), v1.end(), show1);show1.printN();//結論 要點: 分清楚 stl算法返回的值是迭代器 還是 謂詞(函數對象) 是stl算法入門的重要點
}template<typename T>
class IsDiv
{
public:IsDiv(const T &divisor){this->divisor = divisor;}bool operator()(T  &t){return (t%divisor == 0);}protected:
private:T divisor;
};void main03()
{vector<int> v2;for (int i=10; i<33; i++){v2.push_back(i);}int a = 4;IsDiv<int> myDiv(a);//find_if(v2.begin(), v2.end(), myDiv );/*template<class _InIt,class _Pr> inline_InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred){   // find first satisfying _Pred_DEBUG_RANGE(_First, _Last);_DEBUG_POINTER(_Pred);return (_Rechecked(_First,_Find_if(_Unchecked(_First), _Unchecked(_Last), _Pred)));}//find_if返回值是一個迭代器 //要點: 分清楚 stl算法返回的值是迭代器 還是 謂詞(函數對象) 是stl算法入門的重要點*/vector<int>::iterator it;it = find_if(v2.begin(), v2.end(), IsDiv<int>(a) );if (it == v2.end()){cout << "容器中沒有被4整除的元素" << endl;}else{cout <<"第一個是被4整除的元素是:" << *it << endl;}}//二元函數對象
template <typename T>
class SumAdd
{
public:T operator()(T t1, T t2){return t1 + t2;}
};void main04()
{//v1 v2 ==> v3vector<int> v1, v2;vector<int> v3;v1.push_back(1);v1.push_back(3);v1.push_back(5);v2.push_back(2);v2.push_back(4);v2.push_back(6);v3.resize(10);/*template<class _InIt1,class _InIt2,class _OutIt,class _Fn2> inline_OutIt transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func){   // transform [_First1, _Last1) and [_First2, ...) with _Func_DEBUG_RANGE(_First1, _Last1);_DEBUG_POINTER(_Dest);_DEBUG_POINTER(_Func);if (_First1 != _Last1)return (_Transform2(_Unchecked(_First1), _Unchecked(_Last1),_First2, _Dest, _Func,_Is_checked(_Dest)));return (_Dest);}//transform 把運算結果的 迭代器的開始位置 返回出來 */transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SumAdd<int>() );for (vector<int>::iterator it=v3.begin(); it!=v3.end(); it++ ){cout << *it << " ";}cout << endl;
}bool MyCompare(const int &a, const int &b)
{return a < b; //從小到大
}void main05()
{vector<int> v1(10);for (int i=0; i<10; i++){int tmp = rand() %100;v1[i] = tmp;}for (vector<int>::iterator it=v1.begin(); it!=v1.end(); it++ ){cout << *it <<" ";}cout << endl;for_each(v1.begin(), v1.end(), FuncShowElemt2);cout << endl;sort(v1.begin(), v1.end(), MyCompare);for_each(v1.begin(), v1.end(), FuncShowElemt2);cout << endl;
}struct CompareNoCase
{bool operator()(const string &str1, const string &str2){string str1_ ;str1_.resize(str1.size() );transform(str1.begin(), str1.end(), str1_.begin(), tolower ); //預定義函數對象 string str2_ ;str2_.resize(str2.size() );transform(str2.begin(), str2.end(), str2_.begin(), tolower ); //預定義函數對象 return (str1_ < str2_); // 從小到大進行排序}
};
void  main06()
{set<string> set1;set1.insert("bbb");set1.insert("aaa");set1.insert("ccc");set<string>::iterator it = set1.find("aAa"); //find函數 默認 區分大小寫if (it == set1.end()){cout << " 沒有 查找到 aaa " << endl;}else{cout << " 查找到 aaa " << endl;}set<string, CompareNoCase> set2;set2.insert("bbb");set2.insert("aaa");set2.insert("ccc");set<string, CompareNoCase>::iterator it2 = set2.find("aAa");if (it2 == set2.end()){cout << " 沒有 查找到 aaa " << endl;}else{cout << " 不區分大小的的查找  查找到 aaa " << endl;}}void main1111()
{//main01(); //函數對象基本概念//main02(); //函數對象的好處 函數對象做函數參數 函數對象做返回值//main03(); //一元謂詞//main04(); //二元函數對象 和二元謂詞//main05(); //二元函數對象 和二元謂詞main06(); //二元謂詞在set集合中的應用cout<<"hello..."<<endl;system("pause");return ;
}

8.預定義函數對象

標準模板庫STL提前定義了很多預定義函數對象,#include <functional> 必須包含。

//1使用預定義函數對象:
//類模板plus<> 實現了: 不同類型的數據進行加法運算
void main41()
{plus<int> intAdd;int x = 10;int y = 20;int z = intAdd(x, y); //等價于 x + y cout << z << endl;plus<string> stringAdd;string myc = stringAdd("aaa", "bbb");cout << myc << endl;vector<string> v1;v1.push_back("bbb");v1.push_back("aaa");v1.push_back("ccc");v1.push_back("zzzz");//缺省情況下,sort()用底層元素類型的小于操作符以升序排列容器的元素。//為了降序,可以傳遞預定義的類模板greater,它調用底層元素類型的大于操作符:cout << "sort()函數排序" << endl;;sort(v1.begin(), v1.end(), greater<string>() ); //從大到小for (vector<string>::iterator it=v1.begin(); it!=v1.end(); it++ ){cout << *it << endl;}
}

8.1算術函數對象

預定義的函數對象支持加、減、乘、除、求余和取反。調用的操作符是與type相關聯的實例

//加法:plus<Types>
plus<string> stringAdd;
sres = stringAdd(sva1,sva2);減法:minus<Types>
乘法:multiplies<Types>
除法divides<Tpye>
求余:modulus<Tpye>
取反:negate<Type>
negate<int> intNegate;
ires = intNegate(ires);
Ires= UnaryFunc(negate<int>(),Ival1);

8.2關系函數對象

等于equal_to<Tpye>
equal_to<string> stringEqual;
sres = stringEqual(sval1,sval2);
不等于not_equal_to<Type>
大于 greater<Type>
大于等于greater_equal<Type>
小于 less<Type>
小于等于less_equal<Type>
void main42()
{vector<string> v1;v1.push_back("bbb");v1.push_back("aaa");v1.push_back("ccc");v1.push_back("zzzz");v1.push_back("ccc");string s1 = "ccc";//int num = count_if(v1.begin(),v1.end(), equal_to<string>(),s1);int num = count_if(v1.begin(),v1.end(),bind2nd(equal_to<string>(), s1));cout << num << endl;
} 

8.3邏輯函數對象

邏輯與 logical_and<Type>
logical_and<int> indAnd;
ires = intAnd(ival1,ival2);
dres=BinaryFunc( logical_and<double>(),dval1,dval2);
邏輯或logical_or<Type>
邏輯非logical_not<Type>
logical_not<int> IntNot;
Ires = IntNot(ival1);
Dres=UnaryFunc( logical_not<double>,dval1);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448325.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448325.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448325.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安裝 Git ( Windows、linux、Mac)

安裝 Git 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 是時候動手嘗試下 Git 了&#xff0c;不過得先安裝好它。有許多種安裝方式&#xff0c;主要分為兩種&#xff0c;一種是通過編…

會車

概念 會車&#xff0c;即反向行駛的列車、汽車等同時在某一地點交錯通過。 會車攻略 一看&#xff0c;看對向來車的車型、速度和裝載情況&#xff0c;前方道路的寬度、堅實情況&#xff0c;路旁行人、車輛情況&#xff0c;路旁停車以及障礙物情況等; 二算&#xff0c;…

FormsAuthenticationTicket基于forms的驗證

構建基于forms的驗證機制過程如下&#xff1a; 1,設置IIS為可匿名訪問和asp.net web.config中設置為form驗證 2,檢索數據存儲驗證用戶&#xff0c;并檢索角色(如果不是基于角色可不用) 3,使用FormsAuthenticationTicket創建一個Cookie并回發到客戶端&#xff0c;并存儲 角色到票…

通過公共汽車站

要求 通過班車站&#xff0c;應降低速度慢行&#xff0c;掛一擋通過&#xff0c;注意左右仔細查看。操作方法 1、減速慢行&#xff0c;注意觀察公共汽車周圍的交通情況&#xff0c;以防突然情況的出現; 2、在超越公共汽車時&#xff0c;注意提防公共汽車起步后突然向左轉…

STL之函數適配器

1.理論知識 2.常用函數適配器 標準庫提供一組函數適配器&#xff0c;用來特殊化或者擴展一元和二元函數對象。常用適配器是&#xff1a; 1綁定器&#xff08;binder&#xff09;: binder通過把二元函數對象的一個實參綁定到一個特殊的值上&#xff0c;將其轉換成一元函數對象…

真正理解 git fetch, git pull 以及 FETCH_HEAD

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 真正理解 git fetch, git pull 要講清楚git fetch&#xff0c;git pull,必須要附加講清楚git remote&#xff0c;git merge 、遠程rep…

pyqt5 + pyinstaller 制作爬蟲小程序

環境:mac python3.7 pyqt5 pyinstaller ps: 主要是熟悉pyqt5, 加入了單選框 輸入框 文本框 文件夾選擇框及日歷下拉框 效果圖: pyqt5 主程序文件 # -*- coding: utf-8 -*- # Author: Mehaei # Date: 2019-07-10 13:02:56 # Last Modified by: Mehaei # Last Modified time…

通過學校區域

通過學校區域的要求 應觀察前后左右的交通情況&#xff0c;適時減速慢行&#xff0c;不得鳴喇叭和與學生搶行。 操作方法 當駕駛車輛行至學校附近或有注意兒童標志路段時&#xff0c;一定要及時減速&#xff0c;注意觀察道路兩側或周圍的情況&#xff0c;時刻堤防學生橫…

axios中出現兩次請求,OPTIONS請求和GET請求

在項目中發現ajax中出現兩次請求&#xff0c;OPTIONS請求和GET請求 查看到瀏覽器NetWork有兩次請求&#xff0c;請求url一樣&#xff1a; 查找原因是瀏覽器對簡單跨域請求和復雜跨域請求的處理區別。 XMLHttpRequest會遵守同源策略(same-origin policy). 也即腳本只能訪問相同協…

筆試面試收獲(持續更新中)

1. Internet 是有ARPANET發展而來 2. NFS&#xff08;Network File System&#xff09;即網絡文件系統 3. OSI參考模型七層&#xff1a;物理層&#xff0c;數據鏈路層&#xff0c;網絡層&#xff08;IP,路由器&#xff0c;三層交換機&#xff09;&#xff0c;傳輸層&#xff…

Linux 安裝 配置 Maven

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1.需要提前安裝JDK&#xff0c;并且配置環境變量 請參考&#xff1a;https://blog.csdn.net/jiangyu1013/article/details/84321146 2.…

Threading in C#

這里推薦一些C#編程多線程的學習資料&#xff1a; http://knowledge.swanky.wu.googlepages.com/threading_in_c_sharp.html Ebook in English&#xff1a;http://cid-068f7d75d8585700.skydrive.live.com/self.aspx/ebook/threading.pdf 一些demo&#xff1a;http://cid-068f7…

經理人如何與這“六種人”打交道?

在職場中&#xff0c;我們要與不同身份、不同年齡、不同崗位、不同性別、不同性格的人打交道。在平時的實際工作接觸中&#xff0c;善于與不同人打交道的經理人&#xff0c;會根據不同的情況用不同的態度和方式來對待之。 1、如何與死板的人打交道 與這樣的人交往&#xff0c…

[Git高級教程 (一)] 通過 Tag 標簽回退版本修復 bug

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1 前言 本系列之所以取名”Git高級教程”&#xff0c;主要是教大家解決實際工作中遇到的問題&#xff0c;要求讀者會基本的Git用法和命令…

Javascript 自定義輸出

緣由 前段時間再看了一些javascript的學習資料,也寫的一些demo,在輸出的時候一般都用alert,但這個方法會打斷函數運行,用起來不是很好.還有就是console.log這個方法,這種方法原來一直以為只能在FireFox上面才能用,現在才發現主流瀏覽器都支持.但我的這個插件已經寫的差不多了,所…

不要打2歲內和6歲后的孩子 父母必看

一位媽媽說&#xff1a;“孩子經常無理取鬧&#xff0c;到超市就要買這買那&#xff0c;不給買就坐在地上哭鬧。到別人家去就亂翻亂動&#xff0c;還會到人家沙發上亂蹦&#xff0c;無論你怎么說&#xff0c;孩子都不聽話。每次我都會氣不打一處來&#xff0c;回到家就痛打一頓…

設計模式之開放封閉原則

以下皆是個人理解如有不對請留言指出&#xff0c;謝謝&#xff01; 我就代碼提出我自己個人的看法&#xff1a; 正常定義一個類例如銀行工作員&#xff0c;他可以執行存款&#xff0c;付款和轉賬功能&#xff0c;如果在現有功能上我想添加貸款功能&#xff0c;需要在類中添加…

[Git高級教程(二)] 遠程倉庫版本回退方法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1 簡介 最近在使用git時遇到了遠程分支需要版本回滾的情況&#xff0c;于是做了一下研究&#xff0c;寫下這篇博客。 2 問題 如果提交了…

uplift model學習筆記

一、解決的問題&#xff1a; 通常的 Propensity Model 和 Response Model 只是給目標用戶打了個分&#xff0c;并沒有確保模型的結果可以使得活動的提升最大化&#xff1b;它沒有告訴市場營銷人員&#xff0c;哪個用戶最有可能提升活動響應&#xff1b; 因此&#xff0c;需要另…

必須看透的50個錯覺 人生要看透而不看破!

我們應該感謝命運的多喘&#xff0c;是它用歷練使一顆脆弱心的漸漸變得堅強&#xff0c;變得對一切都充滿了向往。無可否認&#xff0c;只有真正的經歷了一些事物之后&#xff0c;你才會對人生看得更加透徹&#xff0c;才會對世間真情感悟的更加真切。 1、個人只能被現實改變…