STL基礎--仿函數(函數對象)
阿新 • • 發佈:2018-12-31
log 需要 emp and 謂詞 code pow 條件 bind2nd
1 首先看個仿函數的例子
class X { public: void operator()(string str) { // 函數調用運算符,返回類型在operator之前 cout << "Calling functor X with parameter " << str<< endl; } operator string () const { return "X"; } //類型轉換函數,返回類型在operator之後 }; int main() { X foo; foo("Hi"); // 以參數HI調用仿函數X } /* * 仿函數的好處: * 1. 智能函數: 比常規函數有更多的功能,比如可以保存狀態(參數化的函數) * 2. 有它自己的類型,不用考慮函數重名問題 * 事實上,類帶來的其他好處,封裝,繼承,多態都可以是仿函數的好處 */
2 參數化的函數
class X { public: X(int i) {} void operator()(string str) { cout << "Calling functor X with parameter " << str<< endl; } }; int main() { X(8)("Hi"); } // 為什麽需要參數化函數,用2個參數的函數代替不行麽? // 只實現+2的功能,如果我想實現加任何數的功能 void add2(int i) { cout << i+2 << endl; } // 用全局變量,顯然不好 // 用模板實現,加任何值的功能,但是val需要編譯時常數 template<int val> void addVal(int i) { cout << val+i << endl; } // 輪到仿函數登場了 class AddValue { int val; public: AddValue(int j) : val(j) { } void operator()(int i) { cout << i+val << endl; } }; int main() { vector<int> vec = { 2, 3, 4, 5}; //for_each(vec.begin(), vec.end(), add2); // {4, 5, 6, 7} int x = 2; //for_each(vec.begin(), vec.end(), addVal<x>); // {4, 5, 6, 7} ,編譯不過 for_each(vec.begin(), vec.end(), AddValue(x)); // {4, 5, 6, 7} }
3 內置的仿函數
// 比較 less greater greater_equal less_equal not_equal_to // 邏輯 logical_and logical_not logical_or // 算術 multiplies minus plus divide modulus negate int x = multiplies<int>()(3,4); // x = 3 * 4 if (not_equal_to<int>()(x, 10)) // if (x != 10) cout << x << endl;
4 參數綁定
set<int> myset = { 2, 3, 4, 5};
vector<int> vec;
int x = multiplies<int>()(3,4); // x = 3 * 4
// 將元素值乘以10,保存在vec中:
transform(myset.begin(), myset.end(), // 源
back_inserter(vec), // 目的
bind(multiplies<int>(), placeholders::_1, 10)); // 仿函數
// multiplies<int>()的第1個參數替換為myset中的元素值
// vec: {20, 30, 40, 50}
void addVal(int i, int val) {
cout << i+val << endl;
}
for_each(vec.begin(), vec.end(), bind(addVal, placeholders::_1, 2));
// C++ 03: bind1st, bind2nd
5 將常規函數轉為仿函數
double Pow(double x, double y) {
return pow(x, y);
}
int main()
{
set<int> myset = {3, 1, 25, 7, 12};
deque<int> d;
auto f = function<double (double,double)>(Pow); //C++ 11
transform(myset.begin(), myset.end(), // 源地址
back_inserter(d), // 目的
bind(f, placeholders::_1, 2)); // 仿函數
// d: {1, 9, 49, 144, 625}
}
// C++ 03中使用ptr_fun
6 lambda函數
// 想拷貝5<x<20之間的元素到d
set<int> myset = {3, 1, 25, 7, 12};
deque<int> d;
// 定義一個函數
bool needCopy(int x){
return (x>20)||(x<5);
}
// 或者用內置仿函數和bind結合
// 兩種方法都不方便
transform(myset.begin(), myset.end(), // source
back_inserter(d), // destination
needCopy
);
/*
bind(logical_or<bool>,
bind(greater<int>(), placeholders::_1, 20),
bind(less<int>(), placeholders::_1, 5))
*/
// C++ 11 lambda function:
transform(myset.begin(), myset.end(), // source
back_inserter(d), // destination
[](int x){return (x>20)||(x<5);} //lambda函數
);
7 為什麽STL中需要仿函數?
set<int> myset = {3, 1, 25, 7, 12}; // myset: {1, 3, 7, 12, 25}
// 同:
set<int, less<int> > myset = {3, 1, 25, 7, 12};
bool lsb_less(int x, int y) {
return (x%10)<(y%10);
}
class Lsb_less {
public:
bool operator()(int x, int y) {
return (x%10)<(y%10);
}
};
int main()
{
set<int, Lsb_less> myset = {3, 1, 25, 7, 12}; // myset: {1,12,3,25,7}
...
}
8 謂詞
/*
* 一種特殊的仿函數:
* 1. 返回一個boolean值
* 2. 不改變數據
*/
class NeedCopy {
bool operator()(int x){
return (x>20)||(x<5);
}
};
transform(myset.begin(), myset.end(), // source
back_inserter(d), // destination
NeedCopy()
);
// 謂詞用於比較或者條件判斷
STL基礎--仿函數(函數對象)