基于C++可變參數(shù)模板格式化字符串

遨游于C++世界時(shí),最討厭的當(dāng)屬于對(duì)c-style的兼容 创葡。

在格式化字符串時(shí)创肥,通常使用的是?snprintf?這個(gè)c函數(shù)。?snprintf?是?sprintf?的安全版瞎访,能夠避免緩沖區(qū)溢出腻贰。

charbuf[1024] = {0};std::strings ="Hello world";snprintf(buf,sizeof(buf),"format str: %s", s.c_str());

snprintf?接受的參數(shù)跟?printf?差不多,都是c-style的數(shù)據(jù)類型扒秸,如?%s?接受的是?const char*?類型的數(shù)據(jù)播演,這就需要我們將?std::string?做一個(gè)轉(zhuǎn)換。這一個(gè)小小的轉(zhuǎn)換讓我覺得非常不爽伴奥,有沒有可能讓?std::string?在做某個(gè)函數(shù)的參數(shù)時(shí)能自動(dòng)做轉(zhuǎn)換写烤?甚至讓一個(gè)將一個(gè)普通的對(duì)象自動(dòng)轉(zhuǎn)換成?const char*?類型?

接下來我們將利用c++11的可變參數(shù)模板(variadic templates)拾徙、參數(shù)包(parameters pack)洲炊、完美轉(zhuǎn)發(fā)(perfect forwarding)等特性來實(shí)現(xiàn)這一想法。

參數(shù)列表完美轉(zhuǎn)發(fā)

寫C++代碼時(shí)锣吼,我滿腦子都是怎么最大限度地提高性能选浑。我們這次的目標(biāo)也一樣,在提供方便的同時(shí)玄叠,不要對(duì)性能有太大影響古徒,甚至不影響。

首先是要將傳入?fmt?函數(shù)的參數(shù)完美轉(zhuǎn)發(fā)至?snprintf?读恃。

templatestringfmt(constchar*format, Args&&... args){charbuf[128] = {0};snprintf(buf,sizeof(buf), format, convert(std::forward(args))...);returnbuf;}

這是一個(gè)可變參數(shù)模板隧膘,args表示傳入的參數(shù)們代态。我們的思路是將傳入的參數(shù)做一個(gè)轉(zhuǎn)換之后傳給?snprintf?。

為了原封不動(dòng)的保持左右值引用疹吃,首先是用?Args&&?代替?Args?的參數(shù)類型蹦疑,此處模板函數(shù)的Args需要編譯器推導(dǎo),所以是一個(gè)通用引用(Universal reference)萨驶,可以指代左值或右值歉摧。用?std::forward<Args>?能保持參數(shù)的左右值性質(zhì),做到參數(shù)的完美轉(zhuǎn)發(fā)腔呜。

自動(dòng)參數(shù)轉(zhuǎn)換

在?convert?這個(gè)函數(shù)中叁温,我們要將特定的類型轉(zhuǎn)換成?const char*?類型,而那些能被?snprintf?接受的類型如?int?,?double?,?char*?核畴,則原封不動(dòng)的返回膝但。

convert?函數(shù)針對(duì)不同的參數(shù)類型需要返回不同的類型。這里也將返回值作為一個(gè)模板類型即可谤草。

templatestructitem_return {usingtype = T&&;};

convert?函數(shù)的定義為:

templateinlinetypenameitem_return::typeconvert(T&& arg){returnstatic_cast(arg);}

convert函數(shù)默認(rèn)將傳入的參數(shù)原封不動(dòng)的返回跟束。接下來我們要做模板的偏特化,對(duì)于指定的對(duì)象丑孩,將其轉(zhuǎn)換為const char *類型

// lvaluetemplate<>structitem_return {usingtype =constchar*;};template<>inlinetypenameitem_return::type convert(obj &arg) {std::cout<<"receive lvalue\n";returnarg.s.c_str();}// rvaluetemplate<>structitem_return {usingtype =constchar*;};template<>inlinetypenameitem_return::type convert(obj &&arg) {std::cout<<"receive rvalue\n";returnarg.s.c_str();}

注意冀宴,返回值也是需要偏特化的。

最后

我構(gòu)造了一個(gè)class嚎杨,hook他的兩個(gè)構(gòu)造函數(shù)以便于觀察是否發(fā)生了拷貝花鹅。

classobj {public:strings;? obj(constchar* ss) {? ? s = ss;? }? obj(constobj& other):s(other.s) {printf("copy constructor\n");? }? obj(obj&& other):s(other.s) {printf("move constructor\n");? ? other.s.clear();? }};

之后我們使用fmt函數(shù),就能像格式化c-style字符串一樣枫浙,格式化任意一個(gè)對(duì)象啦刨肃。

intmain(){obja("haha");intb =3;std::cout<< fmt("%s %s\n%d %d", a, obj("xixi"), b,2) <

運(yùn)行結(jié)果為

receivelvaluereceivervaluehaha xixi32

很好,并沒有發(fā)生拷貝箩帚。

如果有想學(xué)習(xí)c++的程序員真友,可來我們的C/C++學(xué)習(xí)扣qun:589348389,

免費(fèi)送C++的視頻教程噢紧帕!

我每晚上8點(diǎn)還會(huì)在群內(nèi)直播講解C/C++知識(shí)盔然,歡迎大家前來學(xué)習(xí)哦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末是嗜,一起剝皮案震驚了整個(gè)濱河市愈案,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鹅搪,老刑警劉巖站绪,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異丽柿,居然都是意外死亡恢准,警方通過查閱死者的電腦和手機(jī)魂挂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馁筐,“玉大人涂召,你說我怎么就攤上這事∶舫粒” “怎么了果正?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赦抖。 經(jīng)常有香客問我舱卡,道長(zhǎng),這世上最難降的妖魔是什么队萤? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮矫钓,結(jié)果婚禮上要尔,老公的妹妹穿的比我還像新娘。我一直安慰自己新娜,他們只是感情好赵辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著概龄,像睡著了一般还惠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上私杜,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天蚕键,我揣著相機(jī)與錄音,去河邊找鬼衰粹。 笑死锣光,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铝耻。 我是一名探鬼主播誊爹,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瓢捉!你這毒婦竟也來了频丘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤泡态,失蹤者是張志新(化名)和其女友劉穎搂漠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兽赁,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡状答,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年冷守,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惊科。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拍摇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馆截,到底是詐尸還是另有隱情充活,我是刑警寧澤,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布蜡娶,位于F島的核電站混卵,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窖张。R本人自食惡果不足惜幕随,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宿接。 院中可真熱鬧赘淮,春花似錦、人聲如沸睦霎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽副女。三九已至蛤高,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碑幅,已是汗流浹背戴陡。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枕赵,地道東北人猜欺。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拷窜,于是被迫代替她去往敵國(guó)和親开皿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容