一年十二月  誰(shuí)主春秋
關(guān)注:基礎(chǔ)系統(tǒng)工程 密碼學(xué) 人工智能
C++博客
首頁(yè)
新隨筆
聯(lián)系
聚合
管理
隨筆-161 評(píng)論-223 文章-30 trackbacks-0
模板元編程(1):選擇API
C與C++ API的比較
在c語(yǔ)言中,API體現(xiàn)為c函數(shù),如操作系統(tǒng)提供的一系列API,在c++中,API體現(xiàn)為自由函數(shù),這里的自由函數(shù)是指除普通成員函數(shù)、靜態(tài)成員函數(shù)、友元函數(shù)外的能在某命名空間作用域或全局空間內(nèi)直接訪(fǎng)問(wèn)的函數(shù),而這更多地體現(xiàn)為函數(shù)模板,如stl提供的一系列算法swap、count和sort等。相對(duì)于c API,c++ API具有類(lèi)型安全和封閉開(kāi)放的優(yōu)點(diǎn),類(lèi)型安全是因?yàn)閏++本身就是一種比c更強(qiáng)的靜態(tài)類(lèi)型語(yǔ)言,而封閉開(kāi)放是指函數(shù)的設(shè)計(jì)實(shí)現(xiàn)一部分是固定的,而另一部分可以是靈活擴(kuò)展的,這表現(xiàn)為
函數(shù)模板的重載和全局特化
。本文主要講述如何運(yùn)用函數(shù)模板來(lái)設(shè)計(jì)應(yīng)用程序API,并以windows平臺(tái)為例說(shuō)明。
Windows雙版本API
在windows中,很多API通常都有ANSI和UNICODE兩種字符集形式,其命名對(duì)應(yīng)為xxxA和xxxW。如果應(yīng)用層需要針對(duì)這些API來(lái)封裝,為完備起見(jiàn),就需要考慮ANSI和UNICODE兩種版本。一般有兩種方法:第一種是先實(shí)現(xiàn)一個(gè)A(或W)版本,而W(或A)版本的實(shí)現(xiàn)則是在其內(nèi)部將UNICODE(或ANSI)型數(shù)化轉(zhuǎn)化為ANSI(或UNICODE)類(lèi)型,再調(diào)用A(或W)版本,這種方法因需要作字符集的轉(zhuǎn)換來(lái)實(shí)現(xiàn),因而效率較低;第二種是兩個(gè)版本平行實(shí)現(xiàn),即A版本調(diào)用系統(tǒng)A版本API實(shí)現(xiàn),W版本調(diào)用系統(tǒng)W版本API實(shí)現(xiàn),這種方法的缺點(diǎn)是結(jié)果產(chǎn)生除了A或W API調(diào)用不同外很多的重復(fù)代碼。在A和W版本都實(shí)現(xiàn)后,進(jìn)一步,可根據(jù)編譯器的宏定義_UNICODE或UNICODE來(lái)定義一個(gè)自己的API宏。那么除以上兩種方法外,還有沒(méi)有更好的方法呢?而這種方法必然要能夠兼顧效率和避免代碼的重復(fù)冗余。在使用這個(gè)方法前,有下列幾個(gè)問(wèn)題:
1)
如何根據(jù)泛型參數(shù)來(lái)選擇定義正確的結(jié)構(gòu)體,因?yàn)橛行┫到y(tǒng)API的參數(shù)中不僅字符串類(lèi)型有A和W兩種類(lèi)型,而且凡是其內(nèi)部包含字符串類(lèi)型的結(jié)構(gòu)體因而也帶有A和W兩種類(lèi)型。
2)
如何根據(jù)泛型參數(shù)來(lái)選擇調(diào)用正確版本的系統(tǒng)API。
針對(duì)第1個(gè)問(wèn)題,泛型參數(shù)通常只有A或W兩種,因此可以使用選擇特征類(lèi)模板來(lái)實(shí)現(xiàn),如boost中的if_c,softstl中的select_first_type類(lèi)模板,也可以自己實(shí)現(xiàn)這樣的類(lèi)模板。對(duì)第2個(gè)問(wèn)題,與第1個(gè)問(wèn)題不同的是,它是選擇函數(shù)而不是類(lèi)型,本質(zhì)上就是選擇變量,因此需要實(shí)現(xiàn)一種基于類(lèi)型或非類(lèi)型參數(shù)選擇變量的模板,并且使用方式如下
select_variable
<flag>(xxxA,xxxW)(arg1,arg2,...,argN)
flag是一個(gè)布爾非類(lèi)型模板實(shí)參,當(dāng)值為true時(shí)表示選擇返回xxxA,反之選擇返回xxxW,然后接下來(lái)跟著一系列參數(shù),表示調(diào)用對(duì)應(yīng)的A或W版本API,因此select_variable應(yīng)該實(shí)現(xiàn)為函數(shù)模板比較方便,若實(shí)現(xiàn)為類(lèi)模板(關(guān)于實(shí)現(xiàn)可以參考boost中的function),則需要顯式指定函數(shù)返回值和參數(shù)類(lèi)型,這樣一來(lái),當(dāng)函數(shù)參數(shù)過(guò)多,就是一個(gè)噩夢(mèng)了,因?yàn)?/span>
模板實(shí)參演繹不能用于類(lèi)模板及其構(gòu)造函數(shù),只能應(yīng)用于其成員函數(shù)模板
。
綜上分析解決,下面給出select_variable的實(shí)現(xiàn)與應(yīng)用。
select_variable實(shí)現(xiàn)
使用類(lèi)模板特化與函數(shù)模板重載技術(shù)
1
#define
TEMPLATE_BOOL_TRAIT_DEF1(trait,T,c)\
2
template
<
typename T
>
\
3
struct
trait\
4
{\
5
static
const
bool
value
=
c;\
6
}
;\
7
8
#define
TEMPLATE_BOOL_TRAIT_SPEC1(trait,sp,c)\
9
template
<>
\
10
struct
trait
<
sp
>
\
11
{\
12
static
const
bool
value
=
c;\
13
}
;\
14
15
template
<
bool
flag,typename T1,typename T2
>
16
struct
select_type;
17
18
template
<
typename T1,typename T2
>
19
struct
select_type
<
true
,T1,T2
>
20
{
21
typedef T1 type;
22
}
;
23
24
template
<
typename T1,typename T2
>
25
struct
select_type
<
false
,T1,T2
>
26
{
27
typedef T2 type;
28
}
;
29
30
template
<
bool
flag,typename T1,typename T2
>
31
inline typename select_type
<
flag,T1,T2
>
::type select_variable(T1 t1,T2 t2)
32
{
33
return
select_variable_impl(typename select_type
<
flag,
int
,
long
>
::type(),t1,t2);
34
}
35
36
template
<
typename T1,typename T2
>
37
inline T1 select_variable_impl(
int
,T1 t1,T2 t2)
38
{
39
return
t1;
40
}
41
42
template
<
typename T1,typename T2
>
43
inline T2 select_variable_impl(
long
,T1 t1,T2 t2)
44
{
45
return
t2;
46
}
47
48
TEMPLATE_BOOL_TRAIT_DEF1(is_ansi_char,T,
false
)
49
TEMPLATE_BOOL_TRAIT_SPEC1(is_ansi_char,
char
,
true
)
50
TEMPLATE_BOOL_TRAIT_SPEC1(is_ansi_char,
char
const
,
true
)
51
TEMPLATE_BOOL_TRAIT_SPEC1(is_ansi_char,
char
volatile
,
true
)
52
TEMPLATE_BOOL_TRAIT_SPEC1(is_ansi_char,
char
const
volatile
,
true
)
53
54
#undef
TEMPLATE_BOOL_TRAIT_DEF1
55
#undef
TEMPLATE_BOOL_TRAIT_SPEC1
select_variable應(yīng)用
有了select_variable,封裝設(shè)計(jì)API就方便多了,在函數(shù)模板中,類(lèi)型的參數(shù)化體現(xiàn)在其參數(shù)、返回值和內(nèi)部實(shí)現(xiàn)三方面,下面就從這三方面來(lái)說(shuō)明其應(yīng)用:
參數(shù)類(lèi)型化
IsDirectoryOrFile根據(jù)路徑來(lái)判斷是否為目錄或文件,對(duì)于調(diào)用方來(lái)說(shuō),可以靈活指定A或W版本的字符串路徑。
1
template
<
typename charT
>
2
inline
int
I
sDirectoryOrFile(
const
charT
*
path)
3
{
4
DWORD dwFlag
=
select_variable
<
is_ansi_char
<
charT
>
::value
>
(GetFileAttributesA,GetFileAttributesW)(path);
5
if
(INVALID_FILE_ATTRIBUTES
==
dwFlag)
6
return
0
;
7
return
(dwFlag
&
FILE_ATTRIBUTE_DIRECTORY)
?
1
:
2
;
8
}
返回值類(lèi)型化
GetExePath獲取當(dāng)前應(yīng)用程序的路徑,對(duì)于調(diào)用方來(lái)說(shuō),可以靈活指定想要返回A或W版本字符串表示的路徑。
1
template
<
typename T
>
2
inline std::basic_string
<
T
>
GetExePath()
3
{
4
T szExePath[MAX_PATH];
5
select_variable
<
is_ansi_char
<
T
>
::value
>
(GetModuleFileNameA,GetModuleFileNameW)(NULL,szExePath);
6
return
szExePath;
7
}
內(nèi)部實(shí)現(xiàn)類(lèi)型化
GetDirSize計(jì)算某一目錄或文件的大小,因內(nèi)部用到了FirstFirstFile和FirstNextFile,而這兩個(gè)API不僅路徑,而且WIN32_FIND_DATA結(jié)構(gòu)體都有A和W版本,因此需要選擇定義正確的結(jié)構(gòu)體變量和調(diào)用正確的API函數(shù)。
1
template
<
typename charT
>
2
inline ULONGLONG GetDirSize(
const
charT
*
path,
const
volatile
BOOL
&
bExitCalc)
3
{
4
int
ret
=
IsDirectoryOrFile(path);
5
if
(
0
==
ret)
return
0L
;
6
7
std::basic_string
<
charT
>
strPath
=
path;
8
if
(
1
==
ret)
9
{
10
if
(strPath.length()
-
1
!=
strPath.rfind((charT)
'
\\
'
))
11
strPath
+=
(charT)
'
\\
'
;
12
strPath
+=
select_variable
<
is_ansi_char
<
charT
>
::value
>
(
"
*.*
"
,L
"
*.*
"
);
13
}
14
ULONGLONG ullSumSize
=
0
;
15
typename select_type
<
is_ansi_char
<
charT
>
::value,WIN32_FIND_DATAA,WIN32_FIND_DATAW
>
::type findData;
16
HANDLE hFindFile
=
select_variable
<
is_ansi_char
<
charT
>
::value
>
(FindFirstFileA,FindFirstFileW)(strPath.c_str(),
&
findData);
17
18
for
(BOOL bResult
=
(hFindFile
!=
INVALID_HANDLE_VALUE);
bResult; bResult
=
select_variable
<
is_ansi_char
<
charT
>
::value
>
(FindNextFileA,FindNextFileW)(hFindFile,
&
findData))
19
{
20
if
(findData.cFileName[
0
]
==
(charT)
'
.
'
)
21
continue
;
22
if
(findData.dwFileAttributes
&
FILE_ATTRIBUTE_DIRECTORY)
23
{
24
strPath
=
strPath.substr(
0
,strPath.rfind((charT)
'
\\
'
)
+
1
)
+
findData.cFileName;
25
ullSumSize
+=
GetDirSize(strPath.c_str(), bExitCalc);
26
}
27
else
28
ullSumSize
+=
(((ULONGLONG)findData.nFileSizeHigh)
<<
32
)
+
findData.nFileSizeLow;
29
}
30
::FindClose(hFindFile);
31
return
ullSumSize;
32
}
posted on 2011-12-24 19:08
春秋十二月
閱讀(2968)
評(píng)論(2)
編輯
收藏
引用
所屬分類(lèi):
C/C++
評(píng)論:
#
re: 模板應(yīng)用(1) API的設(shè)計(jì)與函數(shù)模板 2011-12-24 21:24 |
萬(wàn)連文
模板這么用有點(diǎn)浪費(fèi)(幾乎是只有一種API調(diào)用方式的實(shí)例化),理論上講你不應(yīng)該在你的代碼中使用MBSC編碼,應(yīng)該采用Unicode編碼,牽扯到的字符使用wchar或者utf8。
模板最好用在架構(gòu)的底層設(shè)計(jì)設(shè)施上,大多是面向語(yǔ)言層面或者純軟件設(shè)計(jì)領(lǐng)域。
回復(fù)
更多評(píng)論
#
re: 模板技術(shù)與應(yīng)用(1): API的設(shè)計(jì)
2012-06-25 16:55 |
liyou
看著就頭大
回復(fù)
更多評(píng)論
刷新評(píng)論列表
只有注冊(cè)用戶(hù)
登錄
后才能發(fā)表評(píng)論。
【推薦】100%開(kāi)源!大型工業(yè)跨平臺(tái)軟件C++源碼提供,建模,組態(tài)!
相關(guān)文章:
使用CString GetBuffer自適應(yīng)獲取計(jì)算機(jī)名稱(chēng)
一種使用函數(shù)指針實(shí)現(xiàn)狀態(tài)機(jī)的方法
重載運(yùn)算符之應(yīng)用: 支持C式結(jié)構(gòu)的一些運(yùn)算
基于策略模式的定制new和delete
一種簡(jiǎn)單的跨平臺(tái)信號(hào)量
一種簡(jiǎn)單的跨平臺(tái)互斥鎖
一種簡(jiǎn)單的跨平臺(tái)用戶(hù)態(tài)自旋鎖
GCC原子操作類(lèi)模板
模板元編程(3):類(lèi)型選擇
模板元編程(2):計(jì)算最值
網(wǎng)站導(dǎo)航:
博客園
IT新聞
BlogJava
博問(wèn)
Chat2DB
管理
本博客所有隨筆均為原創(chuàng),因?yàn)椴欢ㄆ诰S護(hù)更新,所以轉(zhuǎn)載請(qǐng)注明出處,如有問(wèn)題和建議,請(qǐng)留言或評(píng)論,發(fā)表您的寶貴意見(jiàn),藉此平臺(tái)以分享交流、共同進(jìn)步。
聯(lián)系方式:微信math-engineer
<
2025年6月
>
日
一
二
三
四
五
六
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
常用鏈接
我的隨筆
我的評(píng)論
我參與的隨筆
留言簿
(76)
給我留言
查看公開(kāi)留言
查看私人留言
隨筆分類(lèi)
(160)
Algorithm(48)
C/C++(24)
Compiler(25)
Compute Theory(5)
Database(4)
Network(17)
Opensrc(13)
System(24)
隨筆檔案
(161)
2025年6月 (2)
2025年4月 (2)
2024年12月 (1)
2024年11月 (1)
2024年9月 (1)
2024年8月 (2)
2024年6月 (1)
2024年5月 (1)
2024年4月 (1)
2024年3月 (2)
2024年2月 (2)
2023年12月 (1)
2023年11月 (2)
2023年10月 (2)
2023年9月 (37)
2021年12月 (1)
2021年10月 (1)
2021年9月 (1)
2021年2月 (1)
2020年5月 (3)
2020年4月 (1)
2019年11月 (4)
2019年7月 (1)
2018年11月 (1)
2017年12月 (1)
2016年12月 (1)
2016年11月 (2)
2016年10月 (1)
2016年9月 (1)
2016年8月 (3)
2016年7月 (4)
2016年5月 (1)
2015年10月 (2)
2015年9月 (1)
2015年6月 (2)
2015年5月 (3)
2015年2月 (1)
2015年1月 (1)
2014年12月 (2)
2014年4月 (2)
2014年3月 (1)
2014年1月 (1)
2013年10月 (1)
2013年9月 (1)
2013年8月 (3)
2013年5月 (1)
2013年3月 (1)
2012年11月 (1)
2012年9月 (3)
2012年8月 (1)
2012年7月 (1)
2012年6月 (5)
2012年5月 (3)
2011年12月 (5)
2011年11月 (1)
2011年10月 (5)
2011年8月 (7)
2011年7月 (6)
2011年6月 (6)
2010年6月 (1)
2009年12月 (1)
2009年8月 (1)
2009年7月 (1)
2009年6月 (1)
2009年4月 (3)
文章分類(lèi)
(30)
詩(shī)詞作品集(30)
關(guān)注的開(kāi)源項(xiàng)目
LLVM
編譯系統(tǒng)
nginx
高性能Web服務(wù)器
OpenSSL
密碼學(xué)庫(kù)
suricata
網(wǎng)絡(luò)IPS引擎
最新隨筆
1.?一個(gè)歐拉數(shù)整除問(wèn)題的兩種證法
2.?有限域上的特征與指數(shù)和之?dāng)U展
3.?二元二次型的相似變換、正定性與正交分解
4.?關(guān)于群的一些結(jié)論及應(yīng)用
5.?不定方程的代數(shù)數(shù)論解法
6.?關(guān)于橢圓曲線(xiàn)的驗(yàn)證計(jì)算
7.?不可約多項(xiàng)式判別算法的改正
8.?論證有限域上平方根的求解
9.?求解離散對(duì)數(shù)問(wèn)題的Terr算法
10.?簡(jiǎn)單私鑰加密構(gòu)造的驗(yàn)證及安全性分析
積分與排名
積分 - 416971
排名 - 56
最新評(píng)論
1.?re: 一種攔截Linux原始套接字IO的方法[未登錄](méi)
很有前途和很有錢(qián)途啊。
--chipset
2.?re: 一種攔截Linux原始套接字IO的方法[未登錄](méi)
@chipset
是的
--春秋十二月
3.?re: 一種攔截Linux原始套接字IO的方法[未登錄](méi)
工作是做網(wǎng)絡(luò)安全?
--chipset
4.?re: 一種使用函數(shù)指針實(shí)現(xiàn)狀態(tài)機(jī)的方法
函數(shù)指針實(shí)現(xiàn)狀態(tài)機(jī)
--linda
5.?re: 多標(biāo)簽視圖類(lèi)CTabView的設(shè)計(jì)實(shí)現(xiàn)
為啥代碼缺少一些呢,給新手個(gè)完整點(diǎn)的啊
--pekingliu
6.?re: 工作線(xiàn)程與消息循環(huán)
從消息隊(duì)列取出消息 mark了
--mmocake
7.?re: 一種簡(jiǎn)單的跨平臺(tái)套接字管道
評(píng)論內(nèi)容較長(zhǎng),點(diǎn)擊標(biāo)題查看
--IT搬運(yùn)工
8.?re: 一種簡(jiǎn)單的跨平臺(tái)套接字管道
windows僅支持af_init和af_init6地址族有錯(cuò)別字么?
af_init和af_init6
--IT搬運(yùn)工
9.?re: Shell應(yīng)用(8):使用awk定位反匯編輸出[未登錄](méi)
厲害
--Chipset
10.?re: TCP分組丟失時(shí)的狀態(tài)變遷
不錯(cuò)
--Binky
閱讀排行榜
1.?基于OpenSSL實(shí)現(xiàn)的安全連接(14001)
2.?字符串16進(jìn)制顯示(12881)
3.?基于boost asio實(shí)現(xiàn)的ssl socket框架(12342)
4.?Linux套接字與虛擬文件系統(tǒng)(1):初始化和創(chuàng)建(8668)
5.?關(guān)于數(shù)據(jù)庫(kù)的一些學(xué)習(xí)研究心得(8109)
6.?使用CString GetBuffer自適應(yīng)獲取計(jì)算機(jī)名稱(chēng)(7985)
7.?使用正則表達(dá)式解析URL(7949)
8.?basic_string內(nèi)存泄露問(wèn)題之分析解決(7753)
9.?Shell應(yīng)用(4): 使用sed刪除行尾的^M字符(7671)
10.?nginx iocp(1):tcp異步連接(7657)
評(píng)論排行榜
1.?basic_string內(nèi)存泄露問(wèn)題之分析解決(19)
2.?求單向鏈表倒序第m個(gè)元素(11)
3.?基于順序存儲(chǔ)實(shí)現(xiàn)的多叉樹(shù)(1):深度優(yōu)先存儲(chǔ)(9)
4.?字符大小寫(xiě)轉(zhuǎn)換(7)
5.?字符串16進(jìn)制顯示(6)
6.?面向?qū)ο箧i框架的設(shè)計(jì)與實(shí)現(xiàn)(6)
7.?Shell應(yīng)用(4): 使用sed刪除行尾的^M字符(5)
8.?使用正則表達(dá)式解析URL(5)
9.?工作線(xiàn)程與消息循環(huán)(5)
10.?十進(jìn)制整數(shù)千位分隔符(4)
Powered by:
博客園
模板提供:
滬江博客
Copyright ©2025 春秋十二月
亚州日韩精品专区久久久
|
久久久久国产一级毛片高清板
|
国产香蕉久久精品综合网
|
久久精品桃花综合
|
国产精品久久久亚洲
|
久久精品国产亚洲精品
|
亚洲午夜久久久久久久久久
|
97精品国产91久久久久久
|
久久久久人妻一区精品果冻
|
浪潮AV色综合久久天堂
|
久久本道久久综合伊人
|
久久亚洲AV成人无码电影
|
韩国三级中文字幕hd久久精品
|
免费观看久久精彩视频
|
香蕉99久久国产综合精品宅男自
|
人妻久久久一区二区三区
|
久久久99精品一区二区
|
久久久婷婷五月亚洲97号色
|
久久精品一区二区三区中文字幕
|
69久久夜色精品国产69
|
久久热这里只有精品在线观看
|
久久99精品九九九久久婷婷
|
好久久免费视频高清
|
亚洲精品无码久久千人斩
|
亚洲人成无码www久久久
|
99久久精品免费观看国产
|
成人综合伊人五月婷久久
|
99久久精品免费看国产一区二区三区
|
亚州日韩精品专区久久久
|
日本久久久精品中文字幕
|
国产综合久久久久
|
久久久久成人精品无码中文字幕
|
亚洲AV伊人久久青青草原
|
久久av高潮av无码av喷吹
|
久久99国产精品成人欧美
|
久久精品中文字幕有码
|
久久九九久精品国产免费直播
|
国产免费久久精品丫丫
|
久久久久综合中文字幕
|
久久久久99精品成人片三人毛片
|
久久一日本道色综合久久
|