STL基礎--仿函式(函式物件)
阿新 • • 發佈:2018-12-31
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()
);
// 謂詞用於比較或者條件判斷