參數綁定
如果一個函數只在一兩個地方操作,使用Lambad很方便,如果在很多地方操作,編寫多次相同的Lambda函數就很不方便,需要定義函數。但是,定義的函數又不能完全代替能捕捉局部變量的Lambda函數,所以就出現了bind函數。
bind函數是C++11標准庫的函數,需要添加頭文件(g++下加-std=c++11)
#include <functional>
bind就是一個通用的函數適配器,它可以接受一個可調用函數,生成一個新的可調用對象來“適應”原函數的參數列表。
std::bind函數
調用bind函數的方式為:
auto newCallable = bind(callable, arg_list);
說明:
callable
: 本身就是一個可調用的函數
arg_list
: 用逗號分割的參數列表,對應給定的callable參數
當我們調用newCallable時,會調用callable函數,並且將arg_list的參數傳遞給callable函數。
參數占位符
arg_list中有許多占位符,形如_n的名字,其中n是一個整數,表示newCallable的參數的位置比如:_1為newCallable的第一個參數,_2為第二個參數...。
舉例說明:
現在有一個函數:
bool checkSize(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
使用bind生成一個調用checkSize的對象:
auto check = bind(checkSize, _1, 6);
其中的_1表示需要給第一個參數傳遞一個const string&。
string s = "hello";
bool b1 = check(s); //check(s) 會調用checkSize(s, 6)
使用bind,可以將原來的基於Lambda的find_if調用:
auto wc = find_if(words.begin(), words.end(), [sz](const string &a));
改變為使用checkSize版本:
auto wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz));
_n參數說明
\_n
參數都定義在一個名字為placeholders
命名空間中,這個命名空間又在std命名空間中。那么\_1
就是:
using std::placeholders::_1;
對每一個占位符都要使用using聲明,非常麻煩,可以使用:
using namespace std::placeholders;
placeholders的明明空間也定義在functional.h
頭文件中
bind的參數順序
bind綁定的給定函數的參數的順序。比如func是一個函數,它有5個參數,下面對bind的調用:
auto g = bind(fun, a, b, _2, c, _1);
生成一個新的可調用對象,有兩個占位符,傳遞給g的第一個參數綁定到_1,第二個參數綁定到_2,bind調用會將g(_1, _2)
映射為f(a, b, _2, c, _1)
,如:調用g(X, Y)
就會調用f(a, b, Y, c, X)
;
綁定引用參數
默認情況下,bind的非占位符的參數是拷貝到bind返回的可調用的函數中,與Lambda類似,有時候綁定的參數希望用引用的方式傳遞,或不讓綁定的參數類型拷貝。
例如:
for_each(words.begin(), words.end(), [&os, c](const string &s) {os << s << c;});
可以編寫一個函數完成同樣的功能:
ostream &print(ostream &os, const strint &s, char c)
{
return os << s << c;
}
但是:不能直接用bind來代替os的捕獲:
for_each(words.begin(), words.end(), bind(print, os, _1, ' ');
由於不能拷貝一個ostream。如果我們希望bind一個函數而不希望拷貝參數,就需要用標准庫的ref
函數。
for_each(words.begin(), words.end(), bind(printf, ref(os), _1, ' '));
函數ref返回一個對象,包含給定的引用,此對象是可以拷貝的。標准庫中還有cref函數,生成一個保存const引用的類。ref和cref都在頭文件"functional.h"
中
關於bind1st和bind2nd函數
標准庫中定義了這兩個函數,類似於bind,但是這兩個函數只能分別綁定第一個或第二個參數。由於局限性太強,在C++11中已經被棄用,新的C++應該使用bind。