基于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*?類型?

接下來(lái)我們將利用c++11的可變參數(shù)模板(variadic templates)伴奥、參數(shù)包(parameters pack)写烤、完美轉(zhuǎn)發(fā)(perfect forwarding)等特性來(lái)實(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)的返回膝但。接下來(lái)我們要做模板的偏特化,對(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ā)生拷貝仗岖。

看我主頁(yè)簡(jiǎn)介免費(fèi)C++學(xué)習(xí)資源逃延,視頻教程、職業(yè)規(guī)劃轧拄、面試詳解揽祥、學(xué)習(xí)路線、開發(fā)工具

每晚8點(diǎn)直播講解C++編程技術(shù)檩电。

?著作權(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)離奇詭異站绪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)丽柿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門恢准,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人甫题,你說(shuō)我怎么就攤上這事馁筐。” “怎么了坠非?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵敏沉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(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)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼誊爹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起瓢捉,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梢卸。三九已至,卻和暖如春副女,著一層夾襖步出監(jiān)牢的瞬間蛤高,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(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)容