1. 什么是std::function
std::function其實就是一個類模板,含有c的函數(shù)指針概念其障。
類模版std::function是一種通用、多態(tài)的函數(shù)封裝。std::function的實例可以對任何可以調(diào)用的目標實體進行存儲、復制抵窒、和調(diào)用操作,這些目標實體包括普通函數(shù)叠骑、Lambda表達式李皇、函數(shù)指針、以及其它函數(shù)對象等宙枷。
簡要來說:std::function是將所有可調(diào)用的實體封裝起來掉房,形成了一個新的std::function對象茧跋,用戶在使用的時候不需要再去一一調(diào)用實體,只需要使用新的std::function來調(diào)用各實體
如下卓囚,std::function作為回調(diào)函數(shù)使用瘾杭,它可以調(diào)用任何有兩個int形參的返回值為int的對象
#include <iostream>
#include <functional>
#include <list>
using namespace std;
// 傳統(tǒng)C函數(shù)
int c_function(int a, int b)
{
return a + b;
}
// 函數(shù)對象
class Functor
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
int main(int argc, char** argv)
{
Functor functor;
std::list<std::function<int(int, int)>> callables;
callables.push_back(c_function);
callables.push_back(functor);
callables.push_back([](int x, int y)->int{
return x + y;
});
for (const auto& e : callables)
{
cout << e(3, 4) << endl;
}
}
2.std::function作為形參
又因為std::function兼容c的函數(shù)指針,所以它還包含函數(shù)指針應有的特性捍岳。但是它又和函數(shù)指針不同富寿,函數(shù)指針只能指向一個函數(shù),而std::function可以指向任何可以被當做函數(shù)調(diào)用的對象
以下內(nèi)容來自
2.1 基于傳值的方式傳入?yún)?shù)
void registerCallBack(std::function<void()>);
2.2 基于引用的方式傳入?yún)?shù)
因為調(diào)用initWithFunction會產(chǎn)生臨時的std::function對象锣夹,屬于右值页徐,必須使用const,不然會報錯
bool CallFunc::initWithFunction(const std::function<void()> &func)
{
_function = func;
return true;
}
2.3 std::function的保存
轉移操作std::move效率更高
class CallBackHolder
{
public:
void registerCallBack(std::function<void()> func)
{
callback = std::move(func);
}
private:
std::function<void()> callback;
}
3. 類的成員函數(shù)作為函數(shù)入?yún)?/h2>
3.1 使用std::bind()和std::function來實現(xiàn)
std::bind完成了實體和函數(shù)地址的綁定,因為它的參數(shù)里面既有對象指針,又有函數(shù)指針,從而制造了一個std::function,然后std::function只要能正確處理那個this指針,那就能完成正確地調(diào)用了
class RTree
{
public:
void searchOverlap(std::function<void(int)>f)
{
f(2);
}
};
class CallRtree
{
public:
virtual void searchRes(int a)
{
this->a = a;
}
void search()
{
RTree rtree;
std::function<void(int)>functional = std::bind(&CallRtree::searchRes, this, std::placeholders::_1);
//通常直接寫成 auto a =std::bind(....);
rtree.searchOverlap(functional);
int v = this->a;
}
private:
int a;
}
int _tmain(intargc, _TCHAR* argv[])
{
CallRtree caller;
caller.search();
}
3.2 使用lambda表達式實現(xiàn)(先不說了银萍,以后復習了lamdba再來講)
2. 什么是std::bind
- 將函數(shù)变勇、成員函數(shù)和閉包轉成function函數(shù)對象
- 將多元(n>1)函數(shù)轉成一元函數(shù)或者(n-1)元函數(shù)。
bind是一種機制贴唇,可以預先把指定的可調(diào)用的實體的某些參數(shù)綁定到已有的變量搀绣,產(chǎn)生一個新的可調(diào)用實體。
它作為一個通用函數(shù)適配器戳气,接收一個可調(diào)用對象链患,生成一個新的可調(diào)用對象來適應原對象的參數(shù)列表。
2.1 bind的使用方法
比如瓶您,存在一個這樣的函數(shù)check_size麻捻,因為這是一個二元函數(shù),當我們要將它作為find_if的參數(shù)呀袱,會出錯贸毕。因為find_if只接受一元函數(shù),那么如何解決呢夜赵?
一個方法是Lambda表達式明棍,還有一個方法就是使用std::bind
bool check_size(const string &s,string::size_type sz)
{
return s.size()>=sz;
}
下面這個bind的函數(shù)只有一個占位符,即只需要傳入一個參數(shù)寇僧。它將check_size的第二個參數(shù)綁定在sz上摊腋,sz的值就是check_size的第二個參數(shù)的值,而check_size第一個參數(shù)需要傳入
auto wc = find_if(words.begin(),words.end(),bind(check_size,_1,sz));
2.2 bind的參數(shù)問題
auto g = bind(f,a,b,_2,c,_1);
如果現(xiàn)在我們調(diào)用g(3,5)嘁傀,那么就相當于bind(f,a,b,5,c,3);
所以_1相當于傳遞的第一個參數(shù)歌豺,_2相當于傳遞的第二個參數(shù)...以此類推。
需要注意:bind對于直接綁定的值心包,是以值傳遞的方式类咧,對于用_1這類,是使用引用傳遞。bind的返回值是可以調(diào)用的實體痕惋,所以通常我們都會將它和function聯(lián)合在一起使用区宇。
2.3 bind引用參數(shù)
有時候對于有些綁定的參數(shù)我們希望以引用方式傳遞,或者說要綁定的參數(shù)無法拷貝值戳。
比如ostream 流對象是無法拷貝的议谷,那么我們希望將它傳遞給bind而不拷貝它,就需要使用ref堕虹。
ref返回一個對象卧晓,包含給定的引用,是可以拷貝的赴捞。
for_each(words.begin(),words.end,bind(print,ref(os),_1,' '));
2.4 std::bind綁定成員函數(shù)和靜態(tài)成員函數(shù)
對于成員函數(shù)的綁定逼裆,我們一定需要一個調(diào)用者,也就是類的實例赦政!
需要注意的是胜宇,bind無法綁定重載函數(shù),因為當重載函數(shù)的參數(shù)個數(shù)不相同時恢着,bind也失去了它的意義桐愉。
class Utils {
public:
Utils(const char* name) {
strcpy(_name, name);
}
void sayHello(const char* name) const {
std::cout << _name << " say: hello " << name << std::endl;
}
static int getId() {
return 10001;
}
int operator()(int i, int j, int k) const {
return i + j + k;
}
private:
char _name[32];
};
int main(void) {
// 綁定成員函數(shù)
Utils utils("Vicky");
auto sayHello = std::bind(&Utils::sayHello, utils/*調(diào)用者*/, std::placeholders::_1);
sayHello("Jack");
// 綁定靜態(tài)成員函數(shù)
auto getId = std::bind(&Utils::getId);
std::cout << getId() << std::endl;
}
2.5 bind與function搭配
在cocos2dx的源碼中,我們經(jīng)酬桑可以看到function作為函數(shù)形參从诲,而bind作為實參傳入
bool Label::multilineTextWrap(std::function<int(const std::u16string&, int, int)> nextTokenLen)
{}
bool Label::multilineTextWrapByChar()
{
return multilineTextWrap(std::bind(getFirstCharLen, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}