C++提供了多個(gè)包裝器,它們主要是為了給其他編程接口提供更一致或更合適的接口。C++11提供了多個(gè)包裝器,這里我們重點(diǎn)了解一下包裝器function
。
對(duì)于function
, C++ 參考手冊(cè)給出的定義為:
類(lèi)模板 std::function
是通用多態(tài)函數(shù)封裝器。std::function
的實(shí)例能存儲(chǔ)、復(fù)制及調(diào)用任何可調(diào)用 (Callable) 目標(biāo)——函數(shù)、 lambda 表達(dá)式、 bind 表達(dá)式或其他函數(shù)對(duì)象,還有指向成員函數(shù)指針和指向數(shù)據(jù)成員指針。
C++11為什么要引入function
我們先看一個(gè)例子:
#include < iostream >
template < typename T, typename F >
T use_f(T v, F f) {
static int count = 0;
count++;
std::cout < < " use_f count = " < < count < < ", &count = " < < &count
< < std::endl;
return f(v);
}
class Fp {
private:
double z_;
public:
Fp(double z = 1.0) : z_(z) {}
double operator()(double p) { return z_ * p; }
};
class Fq {
private:
double z_;
public:
Fq(double z = 1.0) : z_(z) {}
double operator()(double q) { return z_ + q; }
};
double dub(double x) { return 2.0 * x; }
double square(double x) { return x * x; }
int main() {
using std::cout;
using std::endl;
double y = 1.21;
cout < < "Function pointer dub:n";
/*dub是函數(shù)名(函數(shù)名是一個(gè)指針),
因此參數(shù)F對(duì)應(yīng)的類(lèi)型為double(*)double,
即一個(gè)指向(接受一個(gè)double參數(shù)并返回一個(gè)double的)函數(shù)指針*/
cout < < " " < < use_f(y, dub) < < endl;
cout < < "Function pointer square:n";
cout < < " " < < use_f(y, square) < < endl;//同上
cout < < "Function object Fp:n";
//Fp(5.0)是一個(gè)參數(shù)對(duì)象,F(xiàn)對(duì)應(yīng)的類(lèi)型為Fp
cout < < " " < < use_f(y, Fp(5.0)) < < endl;
cout < < "Function object Fq:n";
//Fq(5.0)是一個(gè)參數(shù)對(duì)象,F(xiàn)對(duì)應(yīng)的類(lèi)型為Fq
cout < < " " < < use_f(y, Fq(5.0)) < < endl;
cout < < "Lambda expression 1:n";
//此處是一個(gè)lambda表達(dá)式,F(xiàn)對(duì)應(yīng)的類(lèi)型為該lambda表達(dá)式使用的類(lèi)型
cout < < " " < < use_f(y, [](double u) { return u * u; }) < < endl;
cout < < "Lambda expression 2:n";
////此處是一個(gè)lambda表達(dá)式,F(xiàn)對(duì)應(yīng)的類(lèi)型為該lambda表達(dá)式使用的類(lèi)型
cout < < " " < < use_f(y, [](double u) { return u + u / 2.0; }) < < endl;
return 0;
}
程序通過(guò)一個(gè)模板函數(shù)use_f
使用參數(shù)f
表示調(diào)用的類(lèi)型,然后將f(v)
返回。在主函數(shù)中我們6次調(diào)用模板函數(shù),對(duì)于前兩個(gè)調(diào)用的use_f
為同一個(gè)實(shí)例化。后面四個(gè),每一個(gè)都有其對(duì)應(yīng)use_f
的實(shí)例化。實(shí)際上,上述代碼的運(yùn)行結(jié)果如下:
Function pointer dub:
use_f count = 1, &count = 0x555555756140
2.42
Function pointer square:
use_f count = 2, &count = 0x555555756140
1.4641
Function object Fp:
use_f count = 1, &count = 0x555555756144
6.05
Function object Fq:
use_f count = 1, &count = 0x555555756148
6.21
Lambda expression 1:
use_f count = 1, &count = 0x555555756138
從運(yùn)行結(jié)果中,我們可以看出,在這六次調(diào)用中use_f
的實(shí)例化了5次。使用模板函數(shù),看似統(tǒng)一了操作形式,但其對(duì)于不同類(lèi)型的F
對(duì)模板函數(shù)都要進(jìn)行一次實(shí)例化,這大大增加了編譯的時(shí)長(zhǎng),并使頭文件也增大,同時(shí)也降低了代碼的執(zhí)行效率。為了解決這類(lèi)問(wèn)題,我們首先能想到的解決辦法就是:降低use_f
的實(shí)例化的次數(shù),理想的情況下是:在這6次循環(huán)調(diào)用的時(shí)候,調(diào)用同一個(gè)use_f
的實(shí)例。針對(duì)上述例子,根據(jù)代碼注釋的分析,如果我們能將這6次調(diào)用中模板函數(shù)中F
的類(lèi)型保持統(tǒng)一,就可以像第一、二次調(diào)用的情況類(lèi)似,使這六次調(diào)用同一個(gè)use_f
的實(shí)例成為可能。
針對(duì)例子中的函數(shù)指針、函數(shù)對(duì)象和lambda表達(dá)式,它們有一個(gè)共同的特征:都是接受一個(gè)double
參數(shù)并返回一個(gè)double
值。也就是它們的調(diào)用特征標(biāo)(它們的特征標(biāo)都是double(double)
)相同。這便是function
解決這個(gè)問(wèn)題的關(guān)鍵?!?注 :調(diào)用特征標(biāo)是由返回類(lèi)型和參數(shù)類(lèi)型列表決定的,其格式為:返回類(lèi)型(參數(shù)類(lèi)型列表)
,其中每個(gè)參數(shù)類(lèi)型用逗號(hào)分隔?!?/p>
因此,C++11引入了function
包裝器。function
包裝器可以簡(jiǎn)單理解為一個(gè)接口,它可以將特征標(biāo)相同的函數(shù)指針、函數(shù)對(duì)象和lambda表達(dá)式等統(tǒng)一定義為一類(lèi)特殊的對(duì)象。
function的用法
包裝器function
的本質(zhì)是一個(gè)模板,它是在頭文件functional
中聲明,其使用方法如下:
template< class >
class function;
template< class R, class... Args >
class function< R(Args...) >;
其中R
為被調(diào)用函數(shù)的返回類(lèi)型,Args
為被調(diào)用函數(shù)的形參。存儲(chǔ)的可調(diào)用對(duì)象被稱(chēng)為std::function
的目標(biāo),如果目標(biāo)為空,則調(diào)用空的function
會(huì)導(dǎo)致拋出std::bad_function_call
異常。
示例:
#include < functional >
#include < iostream >
void print_num(int i) { std::cout < < i < < 'n'; }
int main() {
// 存儲(chǔ)自由函數(shù)
std::function< void(int) > f_display = print_num;
f_display(-9);
// 存儲(chǔ) lambda
std::function< double(double) > f_dub = [](double a) { return 2.0 * a; };
std::cout < < f_dub(2) < < 'n';
// 存儲(chǔ)目標(biāo)為空
std::function< int() > f = nullptr;
try {
f();
} catch (const std::bad_function_call& e) { //拋出異常
std::cout < < e.what() < < 'n';
}
}
輸出結(jié)果為:
-9
4
bad_function_call
在了解完function
的用法之后,回到我們最開(kāi)始的問(wèn)題,其中,6次循環(huán)中要處理的目標(biāo)的特征標(biāo)均為double(double)
,因此,我們班使用function
包裝器將它們將統(tǒng)一“包裝”成function
use_f
將只實(shí)例化一次。使用function
包裝器改進(jìn)后的代碼如下所示:
#include < functional >
#include < iostream >
template < typename T, typename F >
T use_f(T v, F f) {
static int count = 0;
count++;
std::cout < < " use_f count = " < < count < < ", &count = " < < &count
< < std::endl;
return f(v);
}
class Fp {
private:
double z_;
public:
Fp(double z = 1.0) : z_(z) {}
double operator()(double p) { return z_ * p; }
};
class Fq {
private:
double z_;
public:
Fq(double z = 1.0) : z_(z) {}
double operator()(double q) { return z_ + q; }
};
double dub(double x) { return 2.0 * x; }
double square(double x) { return x * x; }
int main() {
using std::cout;
using std::endl;
using std::function;
double y = 1.21;
typedef function< double(double) > fdd; // simplify the type declaration
cout < < "Function pointer dub:n";
cout < < " " < < use_f(y, fdd(dub)) < < endl;
cout < < "Function pointer square:n";
cout < < " " < < use_f(y, fdd(square)) < < endl;
cout < < "Function object Fp:n";
cout < < " " < < use_f(y, fdd(Fq(10.0))) < < endl;
cout < < "Function object Fq:n";
cout < < " " < < use_f(y, fdd(Fp(10.0))) < < endl;
cout < < "Lambda expression 1:n";
cout < < " " < < use_f(y, fdd([](double u) { return u * u; })) < < endl;
cout < < "Lambda expression 2:n";
cout < < " " < < use_f< double >(y, fdd([](double u) { return u + u / 2.0; }))
< < endl;
return 0;
}
輸出結(jié)果為:
Function pointer dub:
use_f count = 1, &count = 0x555555758134
2.42
Function pointer square:
use_f count = 2, &count = 0x555555758134
1.4641
Function object Fp:
use_f count = 3, &count = 0x555555758134
11.21
Function object Fq:
use_f count = 4, &count = 0x555555758134
12.1
Lambda expression 1:
use_f count = 5, &count = 0x555555758134
1.4641
Lambda expression 2:
use_f count = 6, &count = 0x555555758134
1.815
從輸出結(jié)果可以看出,
use_f
確實(shí)只實(shí)例化了一次,增加了編碼效率,6次循環(huán)調(diào)用同一個(gè)函數(shù),增加了代碼額執(zhí)行效率。
總結(jié)
function
包裝器將可調(diào)用對(duì)象的類(lèi)型進(jìn)行統(tǒng)一,便于我們對(duì)其進(jìn)行統(tǒng)一化管理,同時(shí),使用function
包裝器可以解決模板效率低下,實(shí)例化多份的問(wèn)題。
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7649瀏覽量
167315 -
C++語(yǔ)言
+關(guān)注
關(guān)注
0文章
147瀏覽量
7295 -
封裝器
+關(guān)注
關(guān)注
0文章
7瀏覽量
5946
發(fā)布評(píng)論請(qǐng)先 登錄
使用C++11新特性實(shí)現(xiàn)一個(gè)通用的線(xiàn)程池設(shè)計(jì)

C++標(biāo)準(zhǔn)庫(kù)學(xué)習(xí)筆記重點(diǎn)
如何在rt-thread的env環(huán)境中配置C++11?
基于C++11的輕量級(jí)對(duì)象間通信機(jī)制

了解一下貼片電感的特性特點(diǎn)
宏碁智能佛珠了解一下
《深入理解C++11》C++11新特性解析與應(yīng)用的詳細(xì)電子教材免費(fèi)下載
初步感知一下C語(yǔ)言

std::function簡(jiǎn)介及模板類(lèi)聲明
C++11新的類(lèi)功能(特殊成員函數(shù)、override和final)
如何用C++11實(shí)現(xiàn)自旋鎖

評(píng)論