本篇來介紹了C++中bind功能。
1 std::bind
在 C++ 里,std::bind 是一個函數(shù)模板,其作用是創(chuàng)建一個可調(diào)用對象,該對象可綁定到一組參數(shù)上。std::bind 的函數(shù)原型如下:
template<?class?F,?class...?Args?>
/*unspecified*/?bind(?F&&?f,?Args&&...?args?);
template<?class?R,?class?F,?class...?Args?>
/*unspecified*/?bind(?F&&?f,?Args&&...?args?);
參數(shù)
F
:這是要綁定的可調(diào)用對象(像函數(shù)、函數(shù)指針、成員函數(shù)指針、函數(shù)對象等)的類型。
Args
:這是要綁定的參數(shù)的類型包。
f
:需要綁定的可調(diào)用對象。
args
:要綁定到可調(diào)用對象上的參數(shù)。
R
:可調(diào)用對象的返回類型(可選)。
返回值
std::bind
?返回一個未指定類型的可調(diào)用對象,這個對象存儲了?
f
和?args
的副本或者引用,并且可以在后續(xù)被調(diào)用。
2 實例
2.1 基礎(chǔ)的bind功能
被綁定的函數(shù)支持參數(shù)和返回值,參數(shù)通過std::placeholders::_1
的形式,注意這里_1
是特定的形式,表示第一個參數(shù)
//g++ test1.cpp -std=c++11 -o test1
#include?<functional>
#include?<string>
std::string?myFunc(int?a,?float?b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ??returnstd::string(buf);
}
int?main()
{
? ??auto?bindFunc =?std::bind(myFunc,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res = bindFunc(5,?8.63);
? ??printf("res:%sn", res.c_str());
? ??
? ??return0;
}
示例代碼運行結(jié)果如下:
2.2 bind時調(diào)換參數(shù)的順序
如果調(diào)換參數(shù)順序的需求,可以通過指定placeholders的順序,來實現(xiàn)。
比如,myFunc的第二個參數(shù)是float類型,如果在執(zhí)行調(diào)用函數(shù)時,第一個參數(shù)傳入float,則在綁定函數(shù)的第一個位置,寫為?std::placeholders::_2
即可。
//g++ test2.cpp -std=c++11 -o test2
#include?<functional>
#include?<string>
std::string?myFunc(int?a,?float?b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ??returnstd::string(buf);
}
int?main()
{
? ??auto?bindFunc =?std::bind(myFunc,?std::placeholders::_2,?std::placeholders::_1);
? ??std::string?res = bindFunc(3.14,?6);
? ??printf("res:%sn", res.c_str());
? ??
? ??return0;
}
示例代碼運行結(jié)果如下:
2.3 結(jié)合C++類使用bind
上面介紹的函數(shù)都不涉及到類,而C++中一般都會使用類,在類中以及類中的函數(shù),如果使用bind,主要區(qū)別就是要再額外傳入對應(yīng)的類的指針。
這里演示了3種情況:
- MyClass1進(jìn)行一個實例化,然后在main中bind其成員函數(shù)MyClass2是一個單例模式,在main中bind的時候進(jìn)行實例化MyClass3,演示在類內(nèi)部進(jìn)行bind,類的指針就是this指針
//g++ test3.cpp -std=c++11 -o test3
#include?<functional>
#include?<string>
class?MyClass1
{
public:
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? } ? ?
};
class?MyClass2
{
public:
? ??static?MyClass2 &getInstance()
? ??{
? ? ? ??static?MyClass2 instance;
? ? ? ??return?instance;
? ? }
? ??
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? } ? ?
};
class?MyClass3
{
public:
? ??std::string?myFunc(int?a,?float?b)
? ??{
? ? ? ??char?buf[256];
? ? ? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? ? ??returnstd::string(buf);
? ? }?
? ??
? ??void?testBind()
? ??{
? ? ? ??auto?bindFunc =?std::bind(&MyClass3::myFunc,?this,?std::placeholders::_1,?std::placeholders::_2);
? ? ? ??std::string?res = bindFunc(33,?3.45);
? ? ? ??printf("res:%sn", res.c_str());?
? ? } ?
};
int?main()
{
? ? MyClass1 myClass1;
? ??auto?bindFunc1 =?std::bind(&MyClass1::myFunc, &myClass1,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res1 = bindFunc1(11,?1.23);
? ??printf("res:%sn", res1.c_str());
? ??auto?bindFunc2 =?std::bind(&MyClass2::myFunc, MyClass2::getInstance(),?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res2 = bindFunc1(22,?2.34);
? ??printf("res:%sn", res2.c_str());
? ??
? ? MyClass3 myClass3;
? ? myClass3.testBind();
? ? ??
? ??return0;
}
示例代碼運行結(jié)果如下:
2.4 std::ref的使用
在進(jìn)行bind的時候,也可以不使用placeholders占符,直接傳入具體的參數(shù)。
這里要注意,直接傳入值,即使函數(shù)參數(shù)定義的是引用,但實際效果也是按值傳遞。如果需要按引用傳遞,需要使用std::ref,如下例中的第一個演示。當(dāng)然,如果是使用placeholders占符,就不需要考慮std::ref了,就會正常的按定義的引用類型運行。
//g++ test4.cpp -std=c++11 -o test4
#include?<functional>
#include?<string>
std::string?myFunc(int?&a,?float?&b)
{
? ??char?buf[256];
? ??sprintf(buf,?"receive a:%d, b:%.2f", a, b);
? ? a +=?1;
? ? b +=?1;
? ??returnstd::string(buf);
}
int?main()
{
? ??int?a =?100;
? ??float?b =?66.88;
? ??printf("a:%d, b:%.2fn", a, b);
? ??auto?bindFunc1 =?std::bind(myFunc, a,?std::ref(b));
? ??std::string?res1 = bindFunc1();
? ??printf("res1:%sn", res1.c_str());
? ??printf("a:%d, b:%.2fn", a, b);
? ??
? ??auto?bindFunc2 =?std::bind(myFunc,?std::placeholders::_1,?std::placeholders::_2);
? ??std::string?res2 = bindFunc2(a, b);
? ??printf("res2:%sn", res2.c_str());
? ??printf("a:%d, b:%.2fn", a, b);
? ??
? ??return0;
}
示例代碼運行結(jié)果如下:
2.5 將bind作為函數(shù)參數(shù)實現(xiàn)函數(shù)傳遞
最后來看一個特殊的,函數(shù)的參數(shù)是一個函數(shù)類型,如下面的MyClass類中的myFunc,它需要傳入一個函數(shù),這個函數(shù)有兩個float類型的參數(shù),并且返回一個float,在myFunc中定義了兩個參數(shù)的具體的值。
這個有什么用呢,比如在MyCalc類中定義sum求和函數(shù)和sub求差函數(shù),這樣MyClass類就可以使用外部的MyCalc類中定義的函數(shù)功能,來實現(xiàn)一些數(shù)學(xué)運算。
//g++ test5.cpp -std=c++11 -o test5
#include?<functional>
#include?<string>
class?MyCalc
{
public:
? ??float?sum(float?a,?float?b)
? ??{
? ? ? ??return?a + b;
? ? }
? ??float?sub(float?a,?float?b)
? ??{
? ? ? ??return?a - b;
? ? }
};
class?MyClass
{
public:
? ??void?myFunc(std::function<float(float,float)> calcFunc)
? ??{
? ? ? ??float?a =?55;
? ? ? ??float?b =?22;
? ? ? ??float?res = calcFunc(a, b);
? ? ? ??printf("a:%.2f, b:%.2f, res:%.2fn", a, b, res);
? ? }
};
int?main()
{
? ? MyCalc myCalc;
? ? MyClass myClass;
? ??
? ??auto?bindFunc1 =?std::bind(&MyCalc::sum, &myCalc,?std::placeholders::_1,?std::placeholders::_2);
? ? myClass.myFunc(bindFunc1);
? ??
? ??auto?bindFunc2 =?std::bind(&MyCalc::sub, &myCalc,?std::placeholders::_1,?std::placeholders::_2);
? ? myClass.myFunc(bindFunc2);
? ??
? ??return0;
}
示例代碼運行結(jié)果如下:
3 總結(jié)
本篇介紹了C++中bind功能的使用,并通過實際的例里來演示其使用場景。