前言
1. std::bind概述
std::bind
是C++11引入的功能模板,位于<functional>
頭文件中,用于將函數、成員函數或函數對象與特定參數綁定,生成一個新的可調用對象。
1.1 基本用法
#include <iostream>
#include <functional>void print_sum(int a, int b) {std::cout << a + b << std::endl;
}int main() {// 綁定函數和參數auto bound_print = std::bind(print_sum, 10, std::placeholders::_1);bound_print(20); // 輸出30,相當于print_sum(10, 20)return 0;
}
std::bind
?將函數?print_sum
?和部分參數綁定,生成一個新的可調用對象?bound_print
。std::placeholders::_1
?表示調用?bound_print
?時的第一個參數會傳遞給?print_sum
?的第二個形參?b
。綁定時已固定的參數(如?10
)在調用時不再需要傳入。
?默認行為:按值捕獲參數
int x = 10;
auto bound = std::bind(f, x); // x被復制
x = 20;
bound(); // 使用x的副本(值為10)
引用捕獲:使用std::ref或std::cref
int x = 10;
auto bound = std::bind(f, std::ref(x)); // x被引用捕獲
x = 20;
bound(); // 使用x的引用(值為20)
1.2 占位符
std::placeholders::_1
,?_2
, ...,?_N
表示調用時傳入的第1, 2, ..., N個參數。
void print_values(int a, int b, int c) {std::cout << a << ", " << b << ", " << c << std::endl;
}int main() {auto bound_func = std::bind(print_values, std::placeholders::_2,std::placeholders::_1,100);bound_func(10, 20); // 輸出20, 10, 100return 0;
}
調用?bound_func(10, 20)
?時:?_1
?對應第一個實參?10
?→ 傳給原函數的?b
? ?_2
?對應第二個實參?20
?→ 傳給原函數的?a
??c
?始終為固定值?100
1.3 綁定成員函數
綁定成員函數時需要傳入對象指針或引用:
class MyClass {
public:void print(int x) {std::cout << "Value: " << x << std::endl;}
};int main() {MyClass obj;auto bound_member = std::bind(&MyClass::print, &obj, std::placeholders::_1);bound_member(42); // 輸出Value: 42return 0;
}
成員函數指針&MyClass::print
?是?MyClass
?的成員函數?print
?的指針。在 C++ 中,成員函數指針必須通過類的對象(或指針)來調用。std::bind
?綁定成員函數std::bind
?的第一個參數是成員函數指針,第二個參數是對象的指針(&obj
),后續參數是成員函數的參數(用占位符或固定值)。?占位符?_1
std::placeholders::_1
?表示調用?bound_member
?時的第一個參數會傳遞給?print
?的?x
。?調用方式bound_member(42)
2. 完美轉發(Perfect Forwarding)
完美轉發是指在函數模板中將參數以原始類型轉發給另一個函數,保持參數的值類別(左值、右值)不變。
2.1 引用折疊規則
完美轉發基于引用折疊規則:
-
T& &
?→?T&
? ?T& &&
?→?T&
? ??T&& &
?→?T&
? ?T&& &&
?→?T&&
2.2?完美轉發示例
#include <utility>void process(int& x) { std::cout << "lvalue: " << x << std::endl; }
void process(int&& x) { std::cout << "rvalue: " << x << std::endl; }template<typename T>
void wrapper(T&& arg) {process(std::forward<T>(arg)); // 完美轉發
}int main() {int x = 10;wrapper(x); // 調用lvalue版本wrapper(20); // 調用rvalue版本wrapper(std::move(x)); // 調用rvalue版本return 0;
}
?wrapper(x)
(左值)x
?是左值(有名變量),T
?推導為?int&
。std::forward<int&>(arg)
?返回左值引用。調用?process(int&)
,輸出?lvalue: 10
。
wrapper(20)
(右值)20
?是右值(臨時值),T
?推導為?int
。std::forward<int>(arg)
?返回右值引用。調用?process(int&&)
,輸出?rvalue: 20
。
?wrapper(std::move(x))
(右值)std::move(x)
?將?x
?轉為右值,T
?推導為?int
。std::forward<int>(arg)
?返回右值引用。調用?process(int&&)
,輸出?rvalue: 10
。
3. 注意事項
只在模板函數中使用? ?轉發后不要再用該參數、不要重復轉發同一個參數
記住:T&& + forward<T>
?就是完美轉發的全部秘訣
總結
-
std::bind
用于部分應用和參數重排序? ? 完美轉發保持參數的值類別 -
現代C++中優先考慮lambda表達式? ?需要完美轉發時,確保正確使用
std::forward
通過理解這些概念,可以編寫更靈活、高效的C++代碼,特別是在涉及回調、延遲調用和泛型編程的場景中。