C++STL中<functional>的具體使用
C++標(biāo)準(zhǔn)庫(kù)中的 <functional> 庫(kù)是一個(gè)強(qiáng)大的工具集,它提供了用于處理函數(shù)對(duì)象、函數(shù)綁定、函數(shù)包裝等功能的設(shè)施,極大地增強(qiáng)了代碼的靈活性和可復(fù)用性。
1. 函數(shù)對(duì)象(Functors)
函數(shù)對(duì)象,也被稱作仿函數(shù),是重載了 () 運(yùn)算符的類的實(shí)例。其使用方式與普通函數(shù)調(diào)用類似,但函數(shù)對(duì)象可以攜帶狀態(tài),這使得它比普通函數(shù)更加靈活。
#include <iostream>
// 定義一個(gè)函數(shù)對(duì)象類
class Adder {
public:
int operator()(int a, int b) const {
return a + b;
}
};
int main() {
Adder adder;
int result = adder(3, 4);
std::cout << "3 + 4 = " << result << std::endl;
return 0;
}
- 原理:在 Adder 類中,重載了 () 運(yùn)算符,該運(yùn)算符接受兩個(gè) int 類型的參數(shù)并返回它們的和。Adder 類的對(duì)象 adder 就可以像函數(shù)一樣被調(diào)用,當(dāng)調(diào)用 adder(3, 4) 時(shí),實(shí)際上是調(diào)用了 Adder 類的 operator() 方法。
- 優(yōu)點(diǎn):函數(shù)對(duì)象可以包含成員變量,這些成員變量可以在對(duì)象創(chuàng)建時(shí)進(jìn)行初始化,并且在多次調(diào)用 operator() 時(shí)保持狀態(tài),這是普通函數(shù)無法做到的。
2.std::function
std::function 是一個(gè)通用的多態(tài)函數(shù)包裝器,它可以存儲(chǔ)、復(fù)制和調(diào)用任何可調(diào)用對(duì)象,包括普通函數(shù)、函數(shù)指針、成員函數(shù)指針、函數(shù)對(duì)象和 lambda 表達(dá)式等。
#include <iostream>
#include <functional>
// 普通函數(shù)
int add(int a, int b) {
return a + b;
}
int main() {
// 使用 std::function 包裝普通函數(shù)
std::function<int(int, int)> func = add;
int result = func(3, 4);
std::cout << "3 + 4 = " << result << std::endl;
// 包裝 lambda 表達(dá)式
std::function<int(int, int)> lambdaFunc = [](int a, int b) { return a * b; };
result = lambdaFunc(3, 4);
std::cout << "3 * 4 = " << result << std::endl;
return 0;
}
- 模板參數(shù):std::function<int(int, int)> 中的模板參數(shù)指定了可調(diào)用對(duì)象的簽名,即接受兩個(gè) int 類型的參數(shù)并返回一個(gè) int 類型的結(jié)果。
- 包裝過程:當(dāng)將普通函數(shù) add 或 lambda 表達(dá)式賦值給 std::function 對(duì)象時(shí),std::function 會(huì)內(nèi)部存儲(chǔ)該可調(diào)用對(duì)象,并提供統(tǒng)一的調(diào)用接口。當(dāng)調(diào)用 func(3, 4) 或 lambdaFunc(3, 4) 時(shí),std::function 會(huì)根據(jù)存儲(chǔ)的可調(diào)用對(duì)象進(jìn)行相應(yīng)的調(diào)用。
- 用途:std::function 常用于實(shí)現(xiàn)回調(diào)機(jī)制,例如在事件處理、多線程編程等場(chǎng)景中,通過 std::function 可以方便地傳遞和調(diào)用不同類型的可調(diào)用對(duì)象。
3.std::bind
std::bind 用于創(chuàng)建一個(gè)新的可調(diào)用對(duì)象,它將一個(gè)可調(diào)用對(duì)象和其部分或全部參數(shù)綁定在一起,允許進(jìn)行部分參數(shù)綁定和參數(shù)重排。
#include <iostream>
#include <functional>
// 普通函數(shù)
int add(int a, int b) {
return a + b;
}
int main() {
// 使用 std::bind 綁定 add 函數(shù)的第一個(gè)參數(shù)為 3
auto add3 = std::bind(add, 3, std::placeholders::_1);
int result = add3(4);
std::cout << "3 + 4 = " << result << std::endl;
// 參數(shù)重排
auto sub = [](int a, int b) { return a - b; };
auto reversedSub = std::bind(sub, std::placeholders::_2, std::placeholders::_1);
result = reversedSub(3, 4);
std::cout << "4 - 3 = " << result << std::endl;
return 0;
}
- 部分參數(shù)綁定:在 std::bind(add, 3, std::placeholders::_1) 中,add 是要綁定的可調(diào)用對(duì)象,3 是第一個(gè)參數(shù),std::placeholders::_1 是一個(gè)占位符,表示新可調(diào)用對(duì)象的第一個(gè)參數(shù)。add3 是一個(gè)新的可調(diào)用對(duì)象,當(dāng)調(diào)用 add3(4) 時(shí),實(shí)際上是調(diào)用 add(3, 4)。
- 參數(shù)重排:在 std::bind(sub, std::placeholders::_2, std::placeholders::_1) 中,通過占位符的順序交換了 sub 函數(shù)的參數(shù)順序。當(dāng)調(diào)用 reversedSub(3, 4) 時(shí),實(shí)際上是調(diào)用 sub(4, 3)。
- 用途:std::bind 可以用于簡(jiǎn)化函數(shù)調(diào)用,特別是在需要固定部分參數(shù)的情況下,或者在需要對(duì)參數(shù)順序進(jìn)行調(diào)整的情況下。
4.std::mem_fn
std::mem_fn 用于創(chuàng)建一個(gè)可調(diào)用對(duì)象,該對(duì)象可以調(diào)用類的成員函數(shù)。它可以處理成員函數(shù)指針,使得調(diào)用成員函數(shù)更加方便。
#include <iostream>
#include <functional>
class MyClass {
public:
void print() const {
std::cout << "Hello, World!" << std::endl;
}
int add(int a, int b) const {
return a + b;
}
};
int main() {
MyClass obj;
// 使用 std::mem_fn 包裝成員函數(shù)
auto printFunc = std::mem_fn(&MyClass::print);
printFunc(obj);
auto addFunc = std::mem_fn(&MyClass::add);
int result = addFunc(obj, 3, 4);
std::cout << "3 + 4 = " << result << std::endl;
return 0;
}
- 成員函數(shù)指針:&MyClass::print 和 &MyClass::add 是成員函數(shù)指針,它們指向 MyClass 類的 print 和 add 成員函數(shù)。
- 包裝過程:std::mem_fn 接受成員函數(shù)指針作為參數(shù),返回一個(gè)可調(diào)用對(duì)象。當(dāng)調(diào)用 printFunc(obj) 時(shí),std::mem_fn 會(huì)將 obj 作為調(diào)用 print 成員函數(shù)的對(duì)象,從而實(shí)現(xiàn)成員函數(shù)的調(diào)用。同樣,addFunc(obj, 3, 4) 會(huì)調(diào)用 obj 的 add 成員函數(shù),并傳遞 3 和 4 作為參數(shù)。
- 用途:std::mem_fn 使得成員函數(shù)的調(diào)用可以像普通函數(shù)調(diào)用一樣方便,特別是在需要將成員函數(shù)作為參數(shù)傳遞給其他函數(shù)時(shí)非常有用。
5. 預(yù)定義的函數(shù)對(duì)象
<functional> 庫(kù)提供了一系列預(yù)定義的函數(shù)對(duì)象,用于常見的操作,如算術(shù)運(yùn)算、比較運(yùn)算等。
算術(shù)運(yùn)算
#include <iostream>
#include <functional>
int main() {
std::plus<int> add;
int result = add(3, 4);
std::cout << "3 + 4 = " << result << std::endl;
std::minus<int> sub;
result = sub(4, 3);
std::cout << "4 - 3 = " << result << std::endl;
return 0;
}
- std::plus:std::plus<int> 是一個(gè)預(yù)定義的函數(shù)對(duì)象,它重載了 () 運(yùn)算符,用于執(zhí)行兩個(gè) int 類型數(shù)的加法運(yùn)算。當(dāng)調(diào)用 add(3, 4) 時(shí),實(shí)際上是調(diào)用了 std::plus<int> 的 operator() 方法,返回 3 + 4 的結(jié)果。
- std::minus:std::minus<int> 用于執(zhí)行兩個(gè) int 類型數(shù)的減法運(yùn)算,其原理與 std::plus 類似。
比較運(yùn)算
#include <iostream>
#include <functional>
int main() {
std::greater<int> greater;
bool isGreater = greater(4, 3);
std::cout << "4 > 3: " << (isGreater ? "true" : "false") << std::endl;
std::less<int> less;
isGreater = less(4, 3);
std::cout << "4 < 3: " << (isGreater ? "true" : "false") << std::endl;
return 0;
}
- std::greater:std::greater<int> 用于比較兩個(gè) int 類型數(shù)的大小,返回 true 表示第一個(gè)參數(shù)大于第二個(gè)參數(shù)。當(dāng)調(diào)用 greater(4, 3) 時(shí),返回 true。
- std::less:std::less<int> 用于比較兩個(gè) int 類型數(shù)的大小,返回 true 表示第一個(gè)參數(shù)小于第二個(gè)參數(shù)。當(dāng)調(diào)用 less(4, 3) 時(shí),返回 false。
6.std::ref和std::cref
std::ref 和 std::cref 用于創(chuàng)建引用包裝器,當(dāng)需要將引用傳遞給 std::bind 或其他需要按值傳遞參數(shù)的地方時(shí)非常有用。
#include <iostream>
#include <functional>
void increment(int& num) {
++num;
}
int main() {
int num = 3;
auto func = std::bind(increment, std::ref(num));
func();
std::cout << "num = " << num << std::endl;
return 0;
}
- std::ref:std::ref(num) 創(chuàng)建了一個(gè)對(duì) num 的引用包裝器。在 std::bind(increment, std::ref(num)) 中,由于 increment 函數(shù)接受一個(gè)引用參數(shù),使用 std::ref 可以確保傳遞給 increment 的是 num 的引用,而不是 num 的副本。當(dāng)調(diào)用 func() 時(shí),increment 函數(shù)會(huì)修改 num 的值。
- std::cref:std::cref 與 std::ref 類似,但它創(chuàng)建的是一個(gè)常量引用包裝器,用于傳遞常量引用。
7.std::hash
std::hash 是一個(gè)模板類,用于生成對(duì)象的哈希值,常用于實(shí)現(xiàn)哈希表等數(shù)據(jù)結(jié)構(gòu)。
#include <iostream>
#include <functional>
int main() {
std::hash<int> hasher;
int num = 3;
std::size_t hashValue = hasher(num);
std::cout << "Hash value of " << num << " is " << hashValue << std::endl;
return 0;
}
- 哈希函數(shù):std::hash<int> 是一個(gè)針對(duì) int 類型的哈希函數(shù)模板類,它重載了 () 運(yùn)算符,接受一個(gè) int 類型的參數(shù)并返回一個(gè) std::size_t 類型的哈希值。當(dāng)調(diào)用 hasher(num) 時(shí),會(huì)根據(jù) num 的值生成一個(gè)對(duì)應(yīng)的哈希值。
- 用途:在實(shí)現(xiàn)哈希表、哈希集合等數(shù)據(jù)結(jié)構(gòu)時(shí),std::hash 可以方便地為元素生成哈希值,從而實(shí)現(xiàn)快速的查找和插入操作。
8.std::not_fn(C++17 起)
std::not_fn 用于創(chuàng)建一個(gè)新的可調(diào)用對(duì)象,該對(duì)象返回原可調(diào)用對(duì)象結(jié)果的邏輯非。
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
bool isEven(int num) {
return num % 2 == 0;
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
auto isOdd = std::not_fn(isEven);
auto oddCount = std::count_if(numbers.begin(), numbers.end(), isOdd);
std::cout << "Number of odd numbers: " << oddCount << std::endl;
return 0;
}
- 邏輯非操作:std::not_fn(isEven) 創(chuàng)建了一個(gè)新的可調(diào)用對(duì)象 isOdd,當(dāng)調(diào)用 isOdd 時(shí),它會(huì)調(diào)用 isEven 并返回其結(jié)果的邏輯非。在 std::count_if 中使用 isOdd 可以統(tǒng)計(jì) numbers 向量中奇數(shù)的個(gè)數(shù)。
- 用途:std::not_fn 可以方便地反轉(zhuǎn)一個(gè)布爾函數(shù)的邏輯,避免手動(dòng)編寫反轉(zhuǎn)邏輯的代碼。
總結(jié)
<functional> 庫(kù)提供了豐富的工具來處理函數(shù)對(duì)象和函數(shù)調(diào)用,通過這些工具可以提高代碼的靈活性和可維護(hù)性。合理使用這些工具可以讓代碼更加簡(jiǎn)潔和高效,特別是在實(shí)現(xiàn)回調(diào)機(jī)制、函數(shù)綁定、成員函數(shù)調(diào)用等場(chǎng)景中發(fā)揮重要作用。
到此這篇關(guān)于C++STL中<functional>的具體使用的文章就介紹到這了,更多相關(guān)C++STL <functional>內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言結(jié)構(gòu)體內(nèi)存的對(duì)齊知識(shí)詳解
這篇文章主要介紹了C語言結(jié)構(gòu)體內(nèi)存的對(duì)齊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
QT設(shè)置widget背景圖片不影響widget內(nèi)其他控件背景的方法
這篇文章主要給大家介紹了關(guān)于QT設(shè)置widget背景圖片不影響widget內(nèi)其他控件背景的方法,軟件的界面為了更直觀或美觀,常常需要通過圖片來表達(dá),需要的朋友可以參考下2023-06-06
C數(shù)據(jù)結(jié)構(gòu)循環(huán)鏈表實(shí)現(xiàn)約瑟夫環(huán)
這篇文章主要介紹了C數(shù)據(jù)結(jié)構(gòu)循環(huán)鏈表實(shí)現(xiàn)約瑟夫環(huán)的相關(guān)資料,需要的朋友可以參考下2017-05-05
OpenCV實(shí)現(xiàn)圖像的直線檢測(cè)
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)圖像直線檢測(cè)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01

