一年十二月  誰主春秋
關(guān)注:基礎(chǔ)系統(tǒng)工程 密碼學(xué) 人工智能
C++博客
首頁
新隨筆
聯(lián)系
聚合
管理
隨筆-161 評(píng)論-223 文章-30 trackbacks-0
模板元編程(1):選擇API
C與C++ API的比較
在c語言中,API體現(xiàn)為c函數(shù),如操作系統(tǒng)提供的一系列API,在c++中,API體現(xiàn)為自由函數(shù),這里的自由函數(shù)是指除普通成員函數(shù)、靜態(tài)成員函數(shù)、友元函數(shù)外的能在某命名空間作用域或全局空間內(nèi)直接訪問的函數(shù),而這更多地體現(xiàn)為函數(shù)模板,如stl提供的一系列算法swap、count和sort等。相對(duì)于c API,c++ API具有類型安全和封閉開放的優(yōu)點(diǎn),類型安全是因?yàn)閏++本身就是一種比c更強(qiáng)的靜態(tài)類型語言,而封閉開放是指函數(shù)的設(shè)計(jì)實(shí)現(xiàn)一部分是固定的,而另一部分可以是靈活擴(kuò)展的,這表現(xiàn)為
函數(shù)模板的重載和全局特化
。本文主要講述如何運(yùn)用函數(shù)模板來設(shè)計(jì)應(yīng)用程序API,并以windows平臺(tái)為例說明。
Windows雙版本API
在windows中,很多API通常都有ANSI和UNICODE兩種字符集形式,其命名對(duì)應(yīng)為xxxA和xxxW。如果應(yīng)用層需要針對(duì)這些API來封裝,為完備起見,就需要考慮ANSI和UNICODE兩種版本。一般有兩種方法:第一種是先實(shí)現(xiàn)一個(gè)A(或W)版本,而W(或A)版本的實(shí)現(xiàn)則是在其內(nèi)部將UNICODE(或ANSI)型數(shù)化轉(zhuǎn)化為ANSI(或UNICODE)類型,再調(diào)用A(或W)版本,這種方法因需要作字符集的轉(zhuǎn)換來實(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來定義一個(gè)自己的API宏。那么除以上兩種方法外,還有沒有更好的方法呢?而這種方法必然要能夠兼顧效率和避免代碼的重復(fù)冗余。在使用這個(gè)方法前,有下列幾個(gè)問題:
1)
如何根據(jù)泛型參數(shù)來選擇定義正確的結(jié)構(gòu)體,因?yàn)橛行┫到y(tǒng)API的參數(shù)中不僅字符串類型有A和W兩種類型,而且凡是其內(nèi)部包含字符串類型的結(jié)構(gòu)體因而也帶有A和W兩種類型。
2)
如何根據(jù)泛型參數(shù)來選擇調(diào)用正確版本的系統(tǒng)API。
針對(duì)第1個(gè)問題,泛型參數(shù)通常只有A或W兩種,因此可以使用選擇特征類模板來實(shí)現(xiàn),如boost中的if_c,softstl中的select_first_type類模板,也可以自己實(shí)現(xiàn)這樣的類模板。對(duì)第2個(gè)問題,與第1個(gè)問題不同的是,它是選擇函數(shù)而不是類型,本質(zhì)上就是選擇變量,因此需要實(shí)現(xiàn)一種基于類型或非類型參數(shù)選擇變量的模板,并且使用方式如下
select_variable
<flag>(xxxA,xxxW)(arg1,arg2,...,argN)
flag是一個(gè)布爾非類型模板實(shí)參,當(dāng)值為true時(shí)表示選擇返回xxxA,反之選擇返回xxxW,然后接下來跟著一系列參數(shù),表示調(diào)用對(duì)應(yīng)的A或W版本API,因此select_variable應(yīng)該實(shí)現(xiàn)為函數(shù)模板比較方便,若實(shí)現(xiàn)為類模板(關(guān)于實(shí)現(xiàn)可以參考boost中的function),則需要顯式指定函數(shù)返回值和參數(shù)類型,這樣一來,當(dāng)函數(shù)參數(shù)過多,就是一個(gè)噩夢了,因?yàn)?/span>
模板實(shí)參演繹不能用于類模板及其構(gòu)造函數(shù),只能應(yīng)用于其成員函數(shù)模板
。
綜上分析解決,下面給出select_variable的實(shí)現(xiàn)與應(yīng)用。
select_variable實(shí)現(xiàn)
使用類模板特化與函數(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ù)模板中,類型的參數(shù)化體現(xiàn)在其參數(shù)、返回值和內(nèi)部實(shí)現(xiàn)三方面,下面就從這三方面來說明其應(yīng)用:
參數(shù)類型化
IsDirectoryOrFile根據(jù)路徑來判斷是否為目錄或文件,對(duì)于調(diào)用方來說,可以靈活指定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
}
返回值類型化
GetExePath獲取當(dāng)前應(yīng)用程序的路徑,對(duì)于調(diào)用方來說,可以靈活指定想要返回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)類型化
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
春秋十二月
閱讀(2969)
評(píng)論(2)
編輯
收藏
引用
所屬分類:
C/C++
評(píng)論:
#
re: 模板應(yīng)用(1) API的設(shè)計(jì)與函數(shù)模板 2011-12-24 21:24 |
萬連文
模板這么用有點(diǎn)浪費(fèi)(幾乎是只有一種API調(diào)用方式的實(shí)例化),理論上講你不應(yīng)該在你的代碼中使用MBSC編碼,應(yīng)該采用Unicode編碼,牽扯到的字符使用wchar或者utf8。
模板最好用在架構(gòu)的底層設(shè)計(jì)設(shè)施上,大多是面向語言層面或者純軟件設(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)論列表
只有注冊用戶
登錄
后才能發(fā)表評(píng)論。
【推薦】100%開源!大型工業(yè)跨平臺(tái)軟件C++源碼提供,建模,組態(tài)!
相關(guān)文章:
使用CString GetBuffer自適應(yīng)獲取計(jì)算機(jī)名稱
一種使用函數(shù)指針實(shí)現(xiàn)狀態(tài)機(jī)的方法
重載運(yùn)算符之應(yīng)用: 支持C式結(jié)構(gòu)的一些運(yùn)算
基于策略模式的定制new和delete
一種簡單的跨平臺(tái)信號(hào)量
一種簡單的跨平臺(tái)互斥鎖
一種簡單的跨平臺(tái)用戶態(tài)自旋鎖
GCC原子操作類模板
模板元編程(3):類型選擇
模板元編程(2):計(jì)算最值
網(wǎng)站導(dǎo)航:
博客園
IT新聞
BlogJava
博問
Chat2DB
管理
本博客所有隨筆均為原創(chuàng),因?yàn)椴欢ㄆ诰S護(hù)更新,所以轉(zhuǎn)載請(qǐng)注明出處,如有問題和建議,請(qǐng)留言或評(píng)論,發(fā)表您的寶貴意見,藉此平臺(tái)以分享交流、共同進(jìn)步。
聯(lián)系方式:微信math-engineer
<
2011年12月
>
日
一
二
三
四
五
六
27
28
29
30
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
31
1
2
3
4
5
6
7
常用鏈接
我的隨筆
我的評(píng)論
我參與的隨筆
留言簿
(75)
給我留言
查看公開留言
查看私人留言
隨筆分類
(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)
文章分類
(30)
詩詞作品集(30)
關(guān)注的開源項(xiàng)目
LLVM
編譯系統(tǒng)
nginx
高性能Web服務(wù)器
OpenSSL
密碼學(xué)庫
suricata
網(wǎng)絡(luò)IPS引擎
最新隨筆
1.?一個(gè)歐拉數(shù)整除問題的兩種證法
2.?有限域上的特征與指數(shù)和之?dāng)U展
3.?二元二次型的相似變換、正定性與正交分解
4.?關(guān)于群的一些結(jié)論及應(yīng)用
5.?不定方程的代數(shù)數(shù)論解法
6.?關(guān)于橢圓曲線的驗(yàn)證計(jì)算
7.?不可約多項(xiàng)式判別算法的改正
8.?論證有限域上平方根的求解
9.?求解離散對(duì)數(shù)問題的Terr算法
10.?簡單私鑰加密構(gòu)造的驗(yàn)證及安全性分析
積分與排名
積分 - 417363
排名 - 56
最新評(píng)論
1.?re: 一種攔截Linux原始套接字IO的方法[未登錄]
很有前途和很有錢途啊。
--chipset
2.?re: 一種攔截Linux原始套接字IO的方法[未登錄]
@chipset
是的
--春秋十二月
3.?re: 一種攔截Linux原始套接字IO的方法[未登錄]
工作是做網(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)簽視圖類CTabView的設(shè)計(jì)實(shí)現(xiàn)
為啥代碼缺少一些呢,給新手個(gè)完整點(diǎn)的啊
--pekingliu
6.?re: 工作線程與消息循環(huán)
從消息隊(duì)列取出消息 mark了
--mmocake
7.?re: 一種簡單的跨平臺(tái)套接字管道
評(píng)論內(nèi)容較長,點(diǎn)擊標(biāo)題查看
--IT搬運(yùn)工
8.?re: 一種簡單的跨平臺(tái)套接字管道
windows僅支持af_init和af_init6地址族有錯(cuò)別字么?
af_init和af_init6
--IT搬運(yùn)工
9.?re: Shell應(yīng)用(8):使用awk定位反匯編輸出[未登錄]
厲害
--Chipset
10.?re: TCP分組丟失時(shí)的狀態(tài)變遷
不錯(cuò)
--Binky
閱讀排行榜
1.?基于OpenSSL實(shí)現(xiàn)的安全連接(14007)
2.?字符串16進(jìn)制顯示(12887)
3.?基于boost asio實(shí)現(xiàn)的ssl socket框架(12345)
4.?Linux套接字與虛擬文件系統(tǒng)(1):初始化和創(chuàng)建(8680)
5.?關(guān)于數(shù)據(jù)庫的一些學(xué)習(xí)研究心得(8116)
6.?使用CString GetBuffer自適應(yīng)獲取計(jì)算機(jī)名稱(7985)
7.?使用正則表達(dá)式解析URL(7952)
8.?basic_string內(nèi)存泄露問題之分析解決(7756)
9.?Shell應(yīng)用(4): 使用sed刪除行尾的^M字符(7678)
10.?nginx iocp(1):tcp異步連接(7661)
評(píng)論排行榜
1.?basic_string內(nèi)存泄露問題之分析解決(19)
2.?求單向鏈表倒序第m個(gè)元素(11)
3.?基于順序存儲(chǔ)實(shí)現(xiàn)的多叉樹(1):深度優(yōu)先存儲(chǔ)(9)
4.?字符大小寫轉(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.?工作線程與消息循環(huán)(5)
10.?十進(jìn)制整數(shù)千位分隔符(4)
Powered by:
博客園
模板提供:
滬江博客
Copyright ©2025 春秋十二月
99精品国产99久久久久久97
|
亚洲欧美精品一区久久中文字幕
|
欧美亚洲国产精品久久高清
|
性做久久久久久久久浪潮
|
一级做a爰片久久毛片看看
|
热久久国产精品
|
久久强奷乱码老熟女
|
久久精品免费一区二区
|
丁香五月网久久综合
|
岛国搬运www久久
|
亚洲欧美成人久久综合中文网
|
久久精品国产亚洲av瑜伽
|
久久人人青草97香蕉
|
波多野结衣久久精品
|
国产免费久久精品99re丫y
|
99久久免费国产精品特黄
|
九九精品久久久久久噜噜
|
国内精品伊人久久久久777
|
久久亚洲精品成人AV
|
国产精品免费看久久久香蕉
|
日本久久久久久中文字幕
|
国产一区二区精品久久岳
|
人妻无码精品久久亚瑟影视
|
国产欧美久久久精品影院
|
久久综合狠狠综合久久综合88
|
国产精品九九久久免费视频
|
嫩草影院久久国产精品
|
国产午夜精品久久久久九九电影
|
亚洲国产精品无码久久青草
|
中文字幕久久久久人妻
|
av无码久久久久不卡免费网站
|
…久久精品99久久香蕉国产
|
久久综合综合久久97色
|
国内精品久久久久久麻豆
|
久久夜色精品国产亚洲
|
久久99精品久久久久久久久久
|
国产亚洲成人久久
|
99精品久久精品一区二区
|
国产精品伦理久久久久久
|
久久人人爽人人爽人人片AV高清
|
亚洲人成无码www久久久
|