• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-90  評(píng)論-947  文章-0  trackbacks-0
             

            目錄:

            2009-2010小結(jié)(一)畢業(yè)前夕
            2009-2010小結(jié)(二)初入職場(chǎng)
            2009-2010小結(jié)(三)加班考驗(yàn)
            2009-2010小結(jié)(四)抑郁重重
            2009-2010小結(jié)(五)離職始末

            緊接著到了2009年4月份。公司空降了一位主管(稱(chēng)L2吧)。說(shuō)是空降,其實(shí)也不完全是。據(jù)史料記載,在跨國(guó)公司存在以前,他與現(xiàn)在公司的一些中高層曾經(jīng)是同事,后來(lái)歷史推演時(shí),他被留在了老公司。干了幾年休息了一年以后,現(xiàn)在他又到這邊來(lái)了。可是對(duì)于我來(lái)說(shuō),與空降無(wú)異。我心里很是緊張,剛剛才熟悉一個(gè)主管,又要熟悉另一個(gè)陌生的人。

            L2開(kāi)始慢慢接手原來(lái)L1兼管著的Windows端的活。一兩周的相處之后,發(fā)現(xiàn)L2的做事風(fēng)格和L1完全不同。當(dāng)時(shí)對(duì)我來(lái)說(shuō)最不適應(yīng)的是時(shí)間管理。L2總是在下午5點(diǎn)以后來(lái)跟我說(shuō)要做什么事什么事。有時(shí)候會(huì)問(wèn)晚上有事情么,我確實(shí)沒(méi)事情的,老實(shí)回答了,他會(huì)說(shuō)那我們來(lái)看一下某某問(wèn)題。而整個(gè)白天,有時(shí)候幾乎無(wú)所事事。L2自己是個(gè)精力相當(dāng)旺盛的人,也很喜歡加班,幾乎天天加班。有時(shí)候到了晚上9點(diǎn)左右,他會(huì)讓我們“早點(diǎn)回去”,而自己可能還呆著。盡管我很佩服他的精力,可是每當(dāng)在晚上聽(tīng)到“早點(diǎn)回去”的話(huà),一種無(wú)形的怒火便油然而生。

            我徹底地感到恥辱。我想我一個(gè)堂堂正規(guī)大學(xué)畢業(yè)生,雖說(shuō)不上怎么厲害,但還是自認(rèn)為可以好好完成任務(wù)的。你怎么可以讓我加班?還三天兩頭加?還有事沒(méi)事的加?對(duì)了那時(shí)我還有我的畢設(shè)呢,根本沒(méi)法開(kāi)動(dòng)。我陷入了沮喪之中。為此我找L1訴過(guò)一回苦,說(shuō)到傷心處,眼里竟然也會(huì)滲出一些晶瑩的東西。

            畢設(shè)不緊不慢地進(jìn)行著。導(dǎo)師讓我們每?jī)扇芘鲱^一次。之前交給我的數(shù)據(jù)庫(kù)設(shè)計(jì)等工作我在一開(kāi)始就呈上去了,經(jīng)過(guò)討論修改之后差不多定下來(lái)了。導(dǎo)師告知大家做的過(guò)程中如果有數(shù)據(jù)庫(kù)修改要跟我討論過(guò)才可以改,并且讓我如果有問(wèn)題可以召集大家開(kāi)小會(huì)——這讓我備受壓力。我極力推薦使用 SVN 管理和共享所有資料,被采納了。于是我平時(shí)也經(jīng)常看看他們做了什么。除了個(gè)別比較認(rèn)真的在不斷地嘗試、不斷地更新、不斷地改進(jìn)外,其他人基本上沒(méi)怎么動(dòng)。我也稍就微動(dòng)動(dòng),保持著比最勤快的人不勤快,比其他人都勤快的位置。但是大家平均下來(lái),每人一個(gè)頁(yè)面還不到。邏輯層代碼那一塊幾乎沒(méi)有別人在動(dòng)。每次我們碰頭的時(shí)候?qū)熆偸且环N失望的眼神看著我們。到了5月底,只剩最后一周了,我終于不得不請(qǐng)假回來(lái)了。那時(shí)幾乎是公司最忙的時(shí)候。

            那一周也是我們最忙的時(shí)候。所有人都在做畢設(shè)——當(dāng)然白天也還是操作的多。我們組有一兩個(gè)因?yàn)橹疤貏e認(rèn)真,也懂了不少;還有兩個(gè)也是有些編程基礎(chǔ);當(dāng)然也還有人完全不會(huì)的,其中有一個(gè)人自始至終啥事也沒(méi)干。時(shí)下大家做的都還是一些臨散的頁(yè)面,能直接用的只有兩三張。于是回來(lái)的那個(gè)晚上我讓大家先暫停一天,然后安排第二天晚上再碰一次面。然后花了一夜把站點(diǎn)后臺(tái)的各個(gè)功能入口,以及有關(guān)用戶(hù)使用方式的玩意兒先整了出來(lái),把現(xiàn)在已有的頁(yè)面放到該放的位置。第二天再碰頭討論具體的整個(gè)使用流程,以及各種疑問(wèn),把全局性的東西讓大家都達(dá)成共識(shí)。接下來(lái)三四天大多數(shù)人也都比之前認(rèn)真地做了自己的部分,到最后一天還有人有沒(méi)有完成的,就只能剝奪其開(kāi)發(fā)權(quán)利讓其他人頂上了,也算馬馬虎虎湊成一整個(gè)玩意兒了。當(dāng)然出自每個(gè)人之手的界面看上去還是不能完全統(tǒng)一。介于我負(fù)責(zé)的那一塊自己也沒(méi)太快搞定,想想算了,就這樣吧。最后答辯的時(shí)候,我們的會(huì)議管理系統(tǒng)看上去其實(shí)還是像模像樣的。結(jié)果當(dāng)然是皆大歡喜,不管大家實(shí)質(zhì)上做沒(méi)做過(guò)啥。只是導(dǎo)師不無(wú)遺憾的說(shuō),應(yīng)該可以做得更好的。我知道我讓他失望了。

            畢設(shè)搞定之后,我又回到了公司。想不到趕上了一個(gè)更激烈的時(shí)期,跨國(guó)公司有史以來(lái)加班最嚴(yán)重的一陣子。6月12號(hào)左右的三天,公司搬家,本來(lái)是放假的,因?yàn)橼s版本,我們十幾號(hào)人卻被要求在某公寓里集體加班。那三天基本上是每晚上到2點(diǎn)以后。我比較撐不住,或者可能“假裝”撐不住,困了就直接到臥室一頭砸下去,等第二天被叫醒。要是凌晨2點(diǎn)以前下班了,那就第二天早上睡到11點(diǎn)多去,直接拿盒飯。反正加班么,調(diào)休少幾個(gè)小時(shí)就少幾個(gè)小時(shí)。哥真的累了。L2怎么看我已經(jīng)不重要了。

            接下來(lái)回學(xué)校的機(jī)會(huì)不多了。每次回去都像客人一樣,心里真不是滋味。此時(shí)我才發(fā)覺(jué),這么早去實(shí)習(xí)是多么的傻逼。同學(xué)們都在升華感情,我卻浪費(fèi)了人生唯一的大學(xué)畢業(yè)時(shí)期。當(dāng)初請(qǐng)假的時(shí)候,L1和V都問(wèn)過(guò)我,畢設(shè)一周之后要不要繼續(xù)請(qǐng)假幾天,我都很敬業(yè)地說(shuō)不用了。我這一生已經(jīng)沒(méi)辦法找回這樣的時(shí)光了,只求后人不要犯我同樣的錯(cuò)誤,如果他確實(shí)認(rèn)為這是個(gè)錯(cuò)誤的話(huà)。直到現(xiàn)在,但凡知道有應(yīng)屆生要提前出來(lái)實(shí)習(xí),只要搭得上話(huà)的,我都勸之好好考慮。

            畢業(yè)證書(shū)搞定之后,我終于可以拿100%的工資了。前面一些月,我用一些血汗錢(qián)買(mǎi)了新的主板,CPU,顯卡,湊成了一臺(tái)新主機(jī)的主要部分。終于用上了獨(dú)顯,真是享受,雖然月光的季節(jié)總是讓我時(shí)不時(shí)地感慨些許。7月份確實(shí)沒(méi)之前那么瘋狂了,但是L2還是三天兩頭下午臨下班布置任務(wù)。這讓我很煩惱,偶爾也問(wèn)V:什么條件下可以換部門(mén)啊?答曰,入職滿(mǎn)一年。我接著說(shuō),那我不是起碼要加班加一年了?因?yàn)閂之前跟我說(shuō)公司不推崇加班的,這時(shí)候V會(huì)面露小尷尬,也跟我說(shuō)過(guò)不好意思之類(lèi)的。實(shí)際狀況也是不怎么加班的——這在三月份確實(shí)是,在L1的部門(mén)現(xiàn)在也是,在其他部門(mén)基本上也是是的多。

            大約9月份的時(shí)候,一進(jìn)去就開(kāi)始做、5月中旬徹底完成的那個(gè)小玩意兒又要出新版本了,還是L1帶。作為那個(gè)項(xiàng)目的始作俑者,我又被劃歸了L1。這讓我相當(dāng)慶幸。可是好景不長(zhǎng),由于一些組織架構(gòu)上的變動(dòng),H要來(lái)帶那個(gè)項(xiàng)目,L1又純粹帶自己的服務(wù)端部門(mén)了。H是我的一面面試官,面試感覺(jué)相當(dāng)好。后來(lái)也有若干次接觸,感覺(jué)他是所學(xué)甚廣,無(wú)所不通。這自然讓同樣所知甚雜的我有點(diǎn)佩服。在L2的帶領(lǐng)和影響下全員加班的日子里,H也是時(shí)有公開(kāi)抱怨的——嗯,價(jià)值觀(guān)還算相近。加上H對(duì)我的知遇之恩吧,我很是欣然地接受了這個(gè)安排——雖然我基本上沒(méi)有拒絕的選擇。

            終于擺脫L2了,終于不用TMD加班了!哦耶~!我懷著夢(mèng)幻的期待,是無(wú)法按捺的情懷……

            [未完待續(xù)]

            posted @ 2011-01-20 23:36 溪流 閱讀(2276) | 評(píng)論 (4)編輯 收藏

            目錄:

            2009-2010小結(jié)(一)畢業(yè)前夕
            2009-2010小結(jié)(二)初入職場(chǎng)
            2009-2010小結(jié)(三)加班考驗(yàn)
            2009-2010小結(jié)(四)抑郁重重
            2009-2010小結(jié)(五)離職始末

            2009年3月2日,是我上班的第一天。不過(guò)這時(shí)候還不叫正式工作,稱(chēng)為實(shí)習(xí)。公司方面說(shuō)因?yàn)楫厴I(yè)證沒(méi)拿到無(wú)法簽訂勞動(dòng)合同。我要承受的代價(jià)就是50%工資。不過(guò)對(duì)于當(dāng)時(shí)還沒(méi)有嘗過(guò)親手賺錢(qián)的滋味的我來(lái)說(shuō),50%也已經(jīng)相當(dāng)豐厚了,至少這個(gè)學(xué)期吃飯問(wèn)題可以自己解決了。

            上班第一天,考研成績(jī)出來(lái)了,我跟預(yù)料的一樣,沒(méi)考上:

            B1E9144DD8637DFA_163_0

            唯一可以得瑟的是,政治果然靠覺(jué)悟啊,我比參加了好些時(shí)日培訓(xùn)班的同學(xué)們也少不了幾分;其余的不堪入目,就不多說(shuō)了,丟臉,還復(fù)習(xí)過(guò)三天呢,沒(méi)復(fù)習(xí)過(guò)還可以說(shuō)說(shuō)。

            我們公司雖小,但兩岸三地有好些分公司呢,再加上米國(guó)總部的 CxO 們,活生生一個(gè)跨國(guó)公司。在跨國(guó)公司的好處非常明顯,常用書(shū)面英語(yǔ)不熟練都不可能。在真實(shí)的 Email 里頭彪英文的感覺(jué)有時(shí)候還是蠻爽的。比較有意思的是,跟臺(tái)北的同事們?cè)贛SN交流的時(shí)候,他們有時(shí)候說(shuō)英文,我就納悶了,你丫不是會(huì)說(shuō)中文嗎?于是回個(gè)中文,還是簡(jiǎn)體的。人家繼續(xù)英文,我就繼續(xù)淡定的國(guó)語(yǔ)伺候。當(dāng)然,為了尋歡作樂(lè),經(jīng)常情況也會(huì)反過(guò)來(lái)。感覺(jué)米國(guó)的同事以及臺(tái)北的同事用英文的時(shí)候,基本上不太考慮太多小語(yǔ)法的,看多了以后,自己寫(xiě)郵件的時(shí)候也就大膽了,差不多意思了就敢亂發(fā)了,還CC一大票人。現(xiàn)在一個(gè)多月沒(méi)寫(xiě)了,有時(shí)候突然想寫(xiě)句英文,明顯憋不出來(lái)了。

            跨國(guó)公司的HR姐姐很親切,暫時(shí)稱(chēng)為V姐吧。特別是打電話(huà)的時(shí)候,從電話(huà)那頭聽(tīng)她的聲音真是一種享受。不過(guò)在電話(huà)這頭聽(tīng)她給別人打電話(huà),就不是那么唯美了,稍微顯得嗲了點(diǎn)。難道經(jīng)過(guò)電路傳輸,語(yǔ)音會(huì)得到稀釋嗎?從2008年末開(kāi)始接觸,一直到現(xiàn)在,V姐一直給人無(wú)微不至的感覺(jué)。都說(shuō)HR不可信,可是可信不可信又有什么重要呢?我有一個(gè)觀(guān)點(diǎn),特別想跟懷疑論者、陰謀論者分享,不管別人自認(rèn)為是否對(duì)你好,只要那個(gè)人所做的事在你看來(lái)都對(duì)你好的,或者至少不壞,那么TA就是對(duì)你好的,即便人家的本意是想對(duì)你使壞。何謂好?何為壞?都是主觀(guān)感受而已,我們生活在一個(gè)充滿(mǎn)著主觀(guān)意味的世界里,我們需要憑我們的感知能力去觀(guān)察世界。于是,存在即被感知,是直觀(guān)的和易于理解的,所謂的客觀(guān),才是人們杜撰出來(lái)的概念。從這個(gè)意義上來(lái)說(shuō),如果我們相信世界是美好的,世界就會(huì)比預(yù)期的美好得多。所以我認(rèn)為我向來(lái)的不以最壞的惡意來(lái)揣摩他人的理念是行得通的。呃,扯遠(yuǎn)了。(批判我可以,不希望看到有人以“孩子,你還年輕”的態(tài)度來(lái)批判。)

            我在跨國(guó)公司的第一任主管是L1姐,一個(gè)年輕的媽媽?zhuān)谒砩涎笠缰笎?ài)。有時(shí)候晚上加班,聽(tīng)她給沒(méi)幾歲的孩子解釋不能回去的理由,以及那種認(rèn)真勁兒、那種語(yǔ)氣,就能感知到她是沉浸在怎樣的幸福中。不過(guò)L1在工作上的態(tài)度還是蠻嚴(yán)肅認(rèn)真的。在上班的第二個(gè)星期,我就參與了實(shí)際項(xiàng)目,而且是個(gè)新小項(xiàng)目。這種機(jī)會(huì)蠻難得的。在L1的指導(dǎo)和要求下,我覺(jué)得我那時(shí)起才開(kāi)始有了一點(diǎn)點(diǎn)設(shè)計(jì)理念。為了得到她的肯定,我會(huì)盡量將代碼組織得漂亮點(diǎn)。之后不久我又被安排同時(shí)參與另一個(gè)項(xiàng)目的維護(hù)工作。看過(guò)現(xiàn)有代碼,才感覺(jué)到大家寫(xiě)的代碼原來(lái)是這樣的糟糕。不太客氣地說(shuō),80%以上的代碼是沒(méi)有經(jīng)過(guò)好好組織的,90%以上的代碼的書(shū)寫(xiě)是不工整的,以至于當(dāng)時(shí)在手的那個(gè)新項(xiàng)目看上去爽多了。大概那時(shí)侯起,我覺(jué)察到老項(xiàng)目與新項(xiàng)目的截然不同的面貌,心里帶上了一些疑問(wèn):是否老項(xiàng)目一開(kāi)始也是很漂亮的呢?是否漂亮的新項(xiàng)目過(guò)些時(shí)日也會(huì)變得面目不堪呢?

            L1一直帶給我的很大幫助是,當(dāng)我面對(duì)復(fù)雜的邏輯不知道如何下手時(shí),她總是能夠迅速給出一套簡(jiǎn)單、明了的方案,簡(jiǎn)單到當(dāng)時(shí)的我也能立刻理解。從她的或詳或簡(jiǎn)的解釋中,能得到很多關(guān)于軟件設(shè)計(jì)上的種種“規(guī)則”,這些規(guī)則,我所見(jiàn)過(guò)的好些多年開(kāi)發(fā)者也不一定能夠總結(jié)出來(lái),不一定能夠很好地遵守,甚至不一定覺(jué)察到。

            有件不幸的事,L1安排我做項(xiàng)目的安裝程序,也就是最后一道工序。當(dāng)時(shí)我求知欲很強(qiáng),多做點(diǎn)事最好,欣然應(yīng)允。到后來(lái)才發(fā)現(xiàn),發(fā)布版本的日子通常會(huì)加班,加班的時(shí)候我是最沒(méi)事做的,經(jīng)常是打醬油到10點(diǎn),然后干幾分鐘活,最后幫忙測(cè)試。最夸張的一次是,被告知要修一個(gè)很緊要的bug,周六晚上趕去通宵加班,修bug本身不是我的事情,我是去等他們修好后打個(gè)包而已。所以一開(kāi)始是沒(méi)事干的,最多幫忙調(diào)試,看看什么問(wèn)題。后來(lái)困了,就趴在桌子上睡覺(jué),直到被叫起,已經(jīng)第二天5、6點(diǎn)了,被告知修好了,然后打包,測(cè)試走人。雖然我大半個(gè)晚上在睡覺(jué),人家在干活,可是通宵的味道并不好受。我也不喜歡沒(méi)事做的加班。

            說(shuō)起加班,不得不再說(shuō)幾句。到目前為止,我都認(rèn)為L(zhǎng)1是跨國(guó)公司里對(duì)項(xiàng)目進(jìn)度控制的最好的一個(gè)主管,時(shí)間觀(guān)念很強(qiáng)。在我忘記或者即將忘記時(shí)間的時(shí)候,總是能得到善意提醒。所以她帶的項(xiàng)目極少加班,需求也被整理的有條不紊,每周都知道要干什么,每天都直到要干什么,即使加班,也知道因何事而加,知道做完什么以后就能離開(kāi)。

            雖然屬于實(shí)習(xí),但是3月份是我這份工作中過(guò)的最開(kāi)心的一段日子,也是成長(zhǎng)蠻快的一段日子。在這里要衷心的謝謝L1在那段時(shí)期以及日后的很多日子里給予的指點(diǎn)、幫助,以及關(guān)心。

            [未完待續(xù)]

            posted @ 2011-01-17 23:29 溪流 閱讀(2303) | 評(píng)論 (16)編輯 收藏

            目錄:

            C++ 下 Function 對(duì)象的實(shí)現(xiàn)(上)
            C++ 下 Function 對(duì)象的實(shí)現(xiàn)(下)

            上篇中,我們實(shí)現(xiàn)了一個(gè)支持 R () 型函數(shù)的 Function。補(bǔ)充說(shuō)明一下,在我們對(duì)成員函數(shù)的支持中,我們是這樣定義的:

            template <typename R, typename T>
            class MemberFunction0 : public FunctionBase0<R>
            {

            private:
                R (T::*m_pMemFun)();
                T *m_pObj;
            };

            Loki 特意在著作中提醒我們,這里的 T 最好不要是函數(shù)類(lèi)型,改為函數(shù)指針類(lèi)型,如此該類(lèi)的支持范圍將擴(kuò)大。如下:

            template <typename R, typename P, typename T>
            class MemberFunction0 : public FunctionBase0<R>
            {
            public:
                R Invoke()
                {
                    return (m_pObj->*m_pMemFun)();
                }

            public:
                MemberFunction0(P pObj, R (T::*pMemFun)())
                    : m_pObj(pObj), m_pMemFun(pMemFun)
                {

                }

            private:
                R (T::*m_pMemFun)();
                P m_pObj;
            };

            于是,P 和 T 的關(guān)系不那么緊密了,P 不一定非要 T* 不可,也可以是諸如 SmartPtr<T> 之類(lèi)的玩意兒。原本只支持傳入一個(gè)對(duì)象和該對(duì)象的成員函數(shù)的,現(xiàn)在變成傳入一個(gè)具有指針概念的東東和一個(gè)成員函數(shù),只要這個(gè)“指針”使用運(yùn)算符 –> 去調(diào)用那個(gè)成員函數(shù)合乎語(yǔ)法即可。

            接下來(lái),我們來(lái)擴(kuò)展這個(gè) Function,以支持擁有數(shù)目在給定上限內(nèi)的任意參數(shù)的函數(shù)。

            我們先來(lái)手工寫(xiě)一下,看看如何支持帶一個(gè)參數(shù)的函數(shù)。首先定義一個(gè)虛基類(lèi):

            template <typename R, typename T0>
            class FunctionBase1
            {
            public:
                virtual R Invoke(T0) = 0;
                virtual ~FunctionBase1() {}
            };

            實(shí)現(xiàn)兩個(gè)版本,分別支持非成員函數(shù)和成員函數(shù):

            template <typename R, typename T0, typename T>
            class Function1 : public FunctionBase1<R, T0>
            {
            public:
                R Invoke(T0 v0)
                {
                    return m_Fun(v0);
                }

            public:
                Function1(const T &fun)
                    : m_Fun(fun)
                {

                }

            private:
                T m_Fun;
            };

            template <typename R, typename P, typename T, typename T0>
            class MemberFunction1 : public FunctionBase1<R, T0>
            {
            public:
                R Invoke(T0 v0)
                {
                    return (m_pObj->*m_pMemFun)(v0);
                }

            public:
                MemberFunction1(P pObj, R (T::*pMemFun)(T0))
                    : m_pObj(pObj), m_pMemFun(pMemFun)
                {

                }

            private:
                R (T::*m_pMemFun)(T0);
                P m_pObj;
            };

            增加一個(gè)函數(shù)引用萃取的偏特化版本:

            template <typename RetType, typename T0>
            struct FunctionTraits<RetType (T0)>
            {
                typedef RetType (&ParamType)(T0);
            };

            增加一個(gè) Function 類(lèi)的偏特化版本:

            template <typename R, typename T0>
            class Function<R (T0)>
            {
            public:
                template <typename T>
                Function(const T &fun)
                    : m_pFunBase(new Function1<R, T0, typename FunctionTraits<T>::ParamType>(fun))
                {
                   
                }

                template <typename P, typename T>
                Function(P pObj, R (T::*pMemFun)(T0))
                    : m_pFunBase(new MemberFunction1<R, P, T, T0>(pObj, pMemFun))
                {

                }

                ~Function()
                {
                    delete m_pFunBase;
                }

                R operator ()(T0 v0)
                {
                    return m_pFunBase->Invoke(v0);
                }

            private:
                FunctionBase1<R, T0> *m_pFunBase;
            };

            現(xiàn)在,我們可以跑一下測(cè)試代碼了:

            Function<int (int)> f1(&intfun1);
            Function<int (int)> f1_(intfun1);
            Function<int (int)> f2(intfunctor1);
            Function<int (int)> f3(&test, &Test::intmem1);

            f1(1);
            f1_(1);
            f2(2);
            f3(3);

            當(dāng)然,void 函數(shù)也是支持的。

            觀(guān)察上面的這些代碼,和我們?cè)谏弦黄械拇a高度一致,不同的是那些模版參數(shù)、偏特化參數(shù)、函數(shù)調(diào)用參數(shù)等地方。

            假如有這么一組宏:
            TYPENAME_DECLARE(n) 被定義為 typename T0, typename T1, …, typename Tn
            TYPENAME_LIST(n) 被定義為 T0, T1, …, Tn
            TYPENAME_VARIABLE(n) 被定義為 T0 v0, T1 v1, …, Tn vn
            VARIABLE_LIST(n) 被定義為 v0, v1, …, vn

            那么我們可以使用一個(gè) n 就寫(xiě)出支持所有具有參數(shù)的函數(shù)的 Function 了。我們拋棄掉上面的 1 系列的所有類(lèi),僅保持上篇留下來(lái)的代碼,然后利用上面 4 個(gè)宏將所有數(shù)字尾巴去掉,于是代碼變成:

            template <typename R, TYPENAME_DECLARE(n)>
            class FunctionBase_##n
            {
            public:
                virtual R Invoke(TYPENAME_LIST(n)) = 0;
                virtual ~FunctionBase_##n() {}
            };


            template <typename R, TYPENAME_DECLARE(n), typename T>
            class Function_##n : public FunctionBase_##n<R, TYPENAME_LIST(n)>
            {
            public:
                R Invoke(TYPENAME_VARIABLE(n))
                {
                    return m_Fun(VARIABLE_LIST(n));
                }

            public:
                Function_##n(const T &fun)
                    : m_Fun(fun)
                {

                }

            private:
                T m_Fun;
            };

            template <typename R, typename P, typename T, TYPENAME_DECLARE(n)>
            class MemberFunction_##n : public FunctionBase_##n<R, TYPENAME_LIST(n)>
            {
            public:
                R Invoke(TYPENAME_VARIABLE(n))
                {
                    return (m_pObj->*m_pMemFun)(VARIABLE_LIST(n));
                }

            public:
                MemberFunction_##n(P pObj, R (T::*pMemFun)(TYPENAME_LIST(n)))
                    : m_pObj(pObj), m_pMemFun(pMemFun)
                {

                }

            private:
                R (T::*m_pMemFun)(TYPENAME_LIST(n));
                P m_pObj;
            };

            template <typename RetType, TYPENAME_DECLARE(n)>
            struct FunctionTraits<RetType (TYPENAME_LIST(n))>
            {
                typedef RetType (&ParamType)(TYPENAME_LIST(n));
            };

            template <typename R, TYPENAME_DECLARE(n)>
            class Function<R (TYPENAME_LIST(n))>
            {
            public:
                template <typename T>
                Function(const T &fun)
                    : m_pFunBase(new Function_##n<R, TYPENAME_LIST(n), typename FunctionTraits<T>::ParamType>(fun))
                {
                   
                }

                template <typename P, typename T>
                Function(P pObj, R (T::*pMemFun)(TYPENAME_LIST(n)))
                    : m_pFunBase(new MemberFunction_##n<R, P, T, TYPENAME_LIST(n)>(pObj, pMemFun))
                {

                }

                ~Function()
                {
                    delete m_pFunBase;
                }

                R operator ()(TYPENAME_VARIABLE(n))
                {
                    return m_pFunBase->Invoke(VARIABLE_LIST(n));
                }

            private:
                FunctionBase_##n<R, TYPENAME_LIST(n)> *m_pFunBase;
            };

            當(dāng)然上面這樣子的代碼是沒(méi)法跑的咯。如果我們將整段代碼定義為一個(gè)宏 BODY(n),然后用類(lèi)似剛才四個(gè)宏的方式定義宏 FUNCTION_IMPLEMENT(n),使得它的含義為 BODY(0), BODY(1), …, BODY(n),所有工作就都完成了。最后只需要丟下一句 FUNCTION_IMPLEMENT(20),就可以支持 0 到 21 個(gè)參數(shù)了。

            最后歸結(jié)為,如何使用宏搞出“T0, T1, …, Tn” 的形式。

            暴力點(diǎn),我們可以這樣:

            #define T_0 T0
            #define T_1 T_0, T1
            #define T_2 T_1, T2
            #define T_3 T_2, T3
            #define T_4 T_3, T4
            #define T_5 T_4, T5
            #define T_6 T_5, T6
            #define T_7 T_6, T7
            #define T_8 T_7, T8
            #define T_9 T_8, T9

            #define T(n) T_##n

            這樣子,對(duì)于上面四個(gè)宏可以,但是對(duì)于最后的 X(n),人工代碼量還是太大了。嗯?X(n)?對(duì),這個(gè) X,必須在 _1、_2、_3 系列宏里面占據(jù)一個(gè)參數(shù)地位,這樣才有那么一點(diǎn)點(diǎn)擴(kuò)展性。考慮換成這樣:

            #define REP_0(macro, n) macro(0)
            #define REP_1(macro, n) REP_0(macro, n), macro(1)
            #define REP_2(macro, n) REP_1(macro, n), macro(2)
            #define REP_3(macro, n) REP_2(macro, n), macro(3)
            #define REP_4(macro, n) REP_3(macro, n), macro(4)
            #define REP_5(macro, n) REP_4(macro, n), macro(5)
            #define REP_6(macro, n) REP_5(macro, n), macro(6)
            #define REP_7(macro, n) REP_6(macro, n), macro(7)
            #define REP_8(macro, n) REP_7(macro, n), macro(8)
            #define REP_9(macro, n) REP_8(macro, n), macro(9)

            #define REP(macro, n)   REP_##n(macro, n)

            然后:

            #define TYPENAME_LIST_PATTERN(n)    T##n
            #define TYPENAME_LIST(n)            REP(TYPENAME_LIST_PATTERN, n)

            這個(gè) TYPENAME_LIST 就是符合上文要求的宏。接下來(lái)如法炮制其余三個(gè):

            #define TYPENAME_DECLARE_PATTERN(n)     typename T##n
            #define TYPENAME_DECLARE(n)             REP(TYPENAME_DECLARE_PATTERN, n)

            #define TYPENAME_VARIABLE_PATTERN(n)    T##n v##n
            #define TYPENAME_VARIABLE(n)            REP(TYPENAME_VARIABLE_PATTERN, n)

            #define VARIABLE_LIST_PATTERN(n)        v##n
            #define VARIABLE_LIST(n)                REP(VARIABLE_LIST_PATTERN, n)

            最后,我們?cè)?#define FUNCTION_IMPLEMENT(n)  REP(BODY, n) 中還存在一點(diǎn)點(diǎn)問(wèn)題。因?yàn)?BODY 中會(huì)含有 TYPENAME_DECLARE 之類(lèi)的宏的使用,而 TYPENAME_DECLARE 正是使用 REP 定義的。這涉及到宏的遞歸展開(kāi),C++預(yù)處理器的規(guī)則是,遇到這樣的情況就停止展開(kāi)。比如,我們 定義 BODY(n) 為 TYPENAME_DECLARE(n),于是 FUNCTION_IMPLEMENT(2) 會(huì)被展成:

            REP(TYPENAME_DECLARE_PATTERN, 0), REP(TYPENAME_DECLARE_PATTERN, 1), REP(TYPENAME_DECLARE_PATTERN, 2)

            上面的 REP 不會(huì)被繼續(xù)展開(kāi)了。

            為此,一個(gè)不太聰明的辦法就是,再定義一組 REP2。嗯,是個(gè)辦法,就這么辦吧。另外我們剛才的 REP 系列沒(méi)有將分隔符作為參數(shù),默認(rèn)使用逗號(hào),而最后一不的 FUNCTION_IMPLEMENT 的重復(fù)中是不能用逗號(hào)的。考慮提取出來(lái)作為參數(shù)。最后我們的所需要的宏系統(tǒng)是:

            #define NIL
            #define COMMA ,

            #define REP_0(macro, splitter, n) macro(0)
            #define REP_1(macro, splitter, n) REP_0(macro, splitter, n) splitter macro(1)
            #define REP_2(macro, splitter, n) REP_1(macro, splitter, n) splitter macro(2)
            #define REP_3(macro, splitter, n) REP_2(macro, splitter, n) splitter macro(3)
            #define REP_4(macro, splitter, n) REP_3(macro, splitter, n) splitter macro(4)
            #define REP_5(macro, splitter, n) REP_4(macro, splitter, n) splitter macro(5)
            #define REP_6(macro, splitter, n) REP_5(macro, splitter, n) splitter macro(6)
            #define REP_7(macro, splitter, n) REP_6(macro, splitter, n) splitter macro(7)
            #define REP_8(macro, splitter, n) REP_7(macro, splitter, n) splitter macro(8)
            #define REP_9(macro, splitter, n) REP_8(macro, splitter, n) splitter macro(9)

            #define REP(macro, splitter, n)   REP_##n(macro, splitter, n)

            #define REP2_0(macro, splitter, n) macro(0)
            #define REP2_1(macro, splitter, n) REP2_0(macro, splitter, n) splitter macro(1)
            #define REP2_2(macro, splitter, n) REP2_1(macro, splitter, n) splitter macro(2)
            #define REP2_3(macro, splitter, n) REP2_2(macro, splitter, n) splitter macro(3)
            #define REP2_4(macro, splitter, n) REP2_3(macro, splitter, n) splitter macro(4)
            #define REP2_5(macro, splitter, n) REP2_4(macro, splitter, n) splitter macro(5)
            #define REP2_6(macro, splitter, n) REP2_5(macro, splitter, n) splitter macro(6)
            #define REP2_7(macro, splitter, n) REP2_6(macro, splitter, n) splitter macro(7)
            #define REP2_8(macro, splitter, n) REP2_7(macro, splitter, n) splitter macro(8)
            #define REP2_9(macro, splitter, n) REP2_8(macro, splitter, n) splitter macro(9)

            #define REP2(macro, splitter, n)   REP2_##n(macro, splitter, n)

            #define TYPENAME_DECLARE_PATTERN(n)     typename T##n
            #define TYPENAME_DECLARE(n)             REP(TYPENAME_DECLARE_PATTERN, COMMA, n)

            #define TYPENAME_LIST_PATTERN(n)        T##n
            #define TYPENAME_LIST(n)                REP(TYPENAME_LIST_PATTERN, COMMA, n)

            #define TYPENAME_VARIABLE_PATTERN(n)    T##n v##n
            #define TYPENAME_VARIABLE(n)            REP(TYPENAME_VARIABLE_PATTERN, COMMA, n)

            #define VARIABLE_LIST_PATTERN(n)        v##n
            #define VARIABLE_LIST(n)                REP(VARIABLE_LIST_PATTERN, COMMA, n)

            #define FUNCTION_IMPLEMENT(n)  REP2(BODY, NIL, n)

            最后,定義一下 FUNCTION_IMPLEMENT(5),就可以支持到 6 個(gè)參數(shù)了。為了支持更多參數(shù),把上面的 REP 以及 REP2 系列多定義一點(diǎn),比如到 50,那么 FUNCTION_IMPLEMENT 的括號(hào)中就可以填 50 以?xún)?nèi)的任意數(shù)了。考慮到宏展開(kāi)對(duì)編譯速度的影響,以及實(shí)際應(yīng)用中函數(shù)參數(shù)的個(gè)數(shù),定為 20 左右比較合適。

            到這里,我們的Function已經(jīng)實(shí)現(xiàn)了預(yù)期目標(biāo)。接下來(lái)我本來(lái)想說(shuō)說(shuō) TypeList 的。可是現(xiàn)在發(fā)現(xiàn)沒(méi)有 TypeList,F(xiàn)unction 跑的通;有了 TypeList,F(xiàn)unction 也不能寫(xiě)的漂亮多少,雖說(shuō)那些重復(fù)部分有一定的減少。Loki 的 Functor 的參數(shù)類(lèi)型是一個(gè)返回值類(lèi)型加上一個(gè) TypeList,是由用戶(hù)直接傳入 TypeList 的,不用由散的類(lèi)型組合出一個(gè)TypeList(但還是要從TypeList中萃取各個(gè)參數(shù)類(lèi)型),因此用在他那里看上去美妙一點(diǎn)點(diǎn)。當(dāng)然,Loki 也在 Functor 外頭包了一層 Function,以支持函數(shù)簽名作為模版參數(shù)的使用方式。有一點(diǎn)不算改觀(guān)的改觀(guān)是,用了 TypeList 以后,就不會(huì)再有 FunctionBase_1, FunctionBase_2 這樣的玩意兒了,取而代之的是一個(gè)統(tǒng)一的 FunctionBase 外加許多偏特化版本,F(xiàn)unction* 和 MemberFunction* 可以分別統(tǒng)一為一個(gè),但是每一個(gè)里頭都需要實(shí)現(xiàn) N 個(gè) Invoke。加上篇幅關(guān)系,我想這里就不說(shuō)這個(gè) TypeList 了。

            代碼清單太長(zhǎng)了,就不貼了,有意者自然能湊起來(lái)。我目前在 xlLib 中的最終實(shí)現(xiàn)見(jiàn) xlFunction.h

            關(guān)于宏,我不知道可以怎樣改進(jìn)。BOOST_PP_REPEAT 貌似可以調(diào)用自身?不知道如何實(shí)現(xiàn)的,求指教。另外@vczh貌似說(shuō)“實(shí)現(xiàn)了一門(mén)可以自己遞歸自己和內(nèi)置列表處理的另一個(gè)宏”,求分享呀求分享。

            2010-01-18 補(bǔ)充:將最外層 Function 的構(gòu)造函數(shù)中的 const T & 直接改為 T,并且拋棄 FunctionTraits,函數(shù)實(shí)體類(lèi)型將在傳遞過(guò)程中直接退化為函數(shù)指針,這樣就能特化出正確的 FunctionHandler。同時(shí)帶來(lái)另一點(diǎn)影響:如果傳入 Functor,字面上將多一次拷貝動(dòng)作。拋開(kāi)這一點(diǎn)微小的性能來(lái)講,這比剛才的 FunctionTraints 要好得多了。

            posted @ 2011-01-17 21:59 溪流 閱讀(4173) | 評(píng)論 (5)編輯 收藏

            目錄:

            C++ 下 Function 對(duì)象的實(shí)現(xiàn)(上)
            C++ 下 Function 對(duì)象的實(shí)現(xiàn)(下)

            起因在上一篇已經(jīng)說(shuō)過(guò)了。現(xiàn)在讓我們直接進(jìn)入主題。本文的目標(biāo)是,讓以下代碼能順利跑起來(lái):

            int intfun0()
            {
                return 1;
            }

            struct _intfunctor0
            {
                int operator()()
                {
                    return 2;
                }

            } intfunctor0;

            struct Test
            {
                int intmem0()
                {
                    return 3;
                }

            } test;

            int main()
            {
                Function<int ()> f1(&intfun0);
                Function<int ()> f1_(intfun0);
                Function<int ()> f2(intfunctor0);
                Function<int ()> f3(&test, &Test::intmem0);

                f1();
                f1_();
                f2();
                f3();

                return 0;
            }

            除了上述例子中顯示的,還要支持有返回值的函數(shù)和沒(méi)返回值的函數(shù),以及有0個(gè)、1個(gè)、2個(gè)、……、MAX 個(gè)參數(shù)的函數(shù),參數(shù)類(lèi)型無(wú)限制。最后實(shí)現(xiàn)的 Function 對(duì)象僅僅可以執(zhí)行就好。(至于是否可拷貝、是否可判斷相等 等問(wèn)題,都是小事,本文暫不考慮。)最后,Bind 概念也不在本文討論范圍之內(nèi)。

            對(duì)于這個(gè)問(wèn)題,我們一開(kāi)始考慮的可能是怎樣統(tǒng)一三種不同形式。有兩個(gè)選擇,第一,使用 C++ 的多態(tài)機(jī)制,最后統(tǒng)一到基類(lèi)指針的類(lèi)型;第二,允許類(lèi)內(nèi)部有冗余變量以及必要的 Flag,用于判斷是哪種形式的函數(shù),要如何執(zhí)行。這樣看起來(lái),第一種方案比第二種爽一點(diǎn)。于是,最初想到的實(shí)現(xiàn)有可能是這樣的:

            先定義一個(gè)虛基類(lèi):

            template <typename R>
            class FunctionBase0
            {
            public:
                virtual R Invoke() = 0;
                virtual ~FunctionBase0() {}
            };

            然后實(shí)現(xiàn)一個(gè)普通函數(shù)/仿函數(shù)的版本:

            template <typename R, typename T>
            class Function0 : public FunctionBase0<R>
            {
            public:
                R Invoke()
                {
                    return m_Fun();
                }

            public:
                Function0(const T &fun)
                    : m_Fun(fun)
                {

                }

            private:
                T m_Fun;
            };

            這里需要說(shuō)明的是,如果是普通函數(shù),T會(huì)被特化成 R() 或者 R (&)() 或者 R(*)(),取決于使用的時(shí)候傳入 fun 還是傳入 &fun。所以不必另外實(shí)現(xiàn)針對(duì) R(*)() 的版本。Loki (姑且就以作品名稱(chēng)乎 Loki 的作者吧,他那個(gè)真名實(shí)在是太長(zhǎng))在他的書(shū)中稱(chēng)之為“做一個(gè),送一個(gè)”。不過(guò)對(duì)于他書(shū)中所說(shuō)的,我有一個(gè)疑惑。Loki 說(shuō)傳入 fun,模版參數(shù) T 會(huì)被特化成 R (&)(),于是一切順利。可是我在操作過(guò)程中發(fā)現(xiàn) T 一直被特化成 R (),于是上述 class 中的 m_Fun 被認(rèn)為是成員函數(shù)而不是成員變量。不知道是為什么,有知道者請(qǐng)不吝指教哈。因?yàn)橐陨显颍疚闹形乙恢庇?&fun 的形式對(duì)待普通函數(shù)。

            再實(shí)現(xiàn)一個(gè)成員函數(shù)的版本:

            template <typename R, typename T>
            class MemberFunction0 : public FunctionBase0<R>
            {
            public:
                R Invoke()
                {
                    return (m_pObj->*m_pMemFun)();
                }

            public:
                MemberFunction0(T *pObj, R (T::*pMemFun)())
                    : m_pObj(pObj), m_pMemFun(pMemFun)
                {

                }

            private:
                R (T::*m_pMemFun)();
                T *m_pObj;
            };

            最后是一個(gè)包裝類(lèi)。如果你可以接受 Function<int> 表示 int(), Function<int, int> 表示 int (int),…,那么這里沒(méi)有多少技巧可言。boost 的那個(gè) function 使用的是函數(shù)簽名作為模版參數(shù),即 Function<int()>,F(xiàn)unction<int (int)> 等形式。如果不太研究語(yǔ)法,可能會(huì)像我一樣,一開(kāi)始會(huì)對(duì)尖括號(hào)里的 int (int) 之類(lèi)的玩意兒不太熟悉,覺(jué)得很牛逼。可是了解了以后,不過(guò)是個(gè)函數(shù)類(lèi)型而已,沒(méi)什么大不了的。Loki 的 Functor 的使用方式是 Functor<int, TYPELIST_0()>,F(xiàn)unctor<int, TYPELIST_1(int)>。其中第一個(gè)模版參數(shù)始終是返回值,第二個(gè)模版參數(shù)是參數(shù)類(lèi)型列表,Loki 使用了他創(chuàng)造的玩意兒 TypeList 使得所有函數(shù)參數(shù)只占一個(gè)坑,這在等下的支持多參數(shù)的擴(kuò)展中能夠帶來(lái)一些美觀(guān)。我比較喜歡 boost 的使用方式,讓使用者直接以語(yǔ)言規(guī)定的形式填入函數(shù)簽名,而不是一些額外的約定(“第一個(gè)模版參數(shù)表示返回值”,“第二個(gè)到最后的模版參數(shù)表示參數(shù)”,“第二個(gè)模版參數(shù)以 TypeList 形式表示函數(shù)參數(shù)”等)。

            為了達(dá)到這個(gè)目標(biāo),我們要玩一些偏特化技巧。關(guān)于偏特化,我一直以來(lái)的膚淺認(rèn)識(shí)都是錯(cuò)誤的。我原以為,對(duì)于模版類(lèi):

            template <typename T0, typename T1>
            class Foo;

            我如果特化其中一個(gè)參數(shù) T1:

            template <typename T0>
            class Foo<T0, int>
            {

            }

            我以為只有這樣才叫偏特化,以為偏特化的過(guò)程總是減少模版參數(shù)的。而實(shí)際上,只要用某個(gè)/些類(lèi)型占據(jù)原始模版參數(shù)的位置,就可以了。比如,對(duì)于上述 Foo,我可以特化一個(gè) class<T0, std::map<U0, U1>>,消去一個(gè) T1,而新增 U0、U1:

            template <typename T0, typename U0, typename U1>
            class Foo<T0, std::map<U0, U1>>
            {

            }

            原來(lái) T1 的位置被 std::map<U0, U1> 占據(jù)了,這也是偏特化。當(dāng)然最后的模版參數(shù)數(shù)量也可以不變,如:

            template <typename T0, typename U>
            class Foo<T0, std::vector<U>>
            {

            }

            以及

            template <typename T0, typename U>
            class Foo<T0, U*>
            {

            }

            其中后者是實(shí)現(xiàn)類(lèi)型萃取的主要方式。只要特化以后,這個(gè)類(lèi)依然帶有至少一個(gè)模版參數(shù),就是偏特化。如果最后產(chǎn)生了 template<> 的形式,那就是完全特化。

            回到我們剛才的主題,我們要提供給用戶(hù)的是這樣一個(gè)類(lèi):

            template <typename Signature>
            class Function;

            其中參數(shù) Signature 會(huì)被實(shí)際的函數(shù)類(lèi)型所特化。但是我們只知道整體的一個(gè) Signature 并沒(méi)有用,我們必須知道被分解開(kāi)來(lái)的返回值類(lèi)型、參數(shù)類(lèi)型。于是,引入一個(gè)偏特化版本:

            template <typename R>
            class Function<R ()>

            這里使用 R () 特化原始的 Signature,引入一個(gè)新的參數(shù) R。于是返回值類(lèi)型 R 就被萃取出來(lái)了。實(shí)現(xiàn)如下:

            template <typename R>
            class Function<R ()>
            {
            public:
                template <typename T>
                Function(const T &fun)
                    : m_pFunBase(new Function0<R, T>(fun))
                {
                   
                }

                template <typename T>
                Function(T *pObj, R (T::*pMemFun)())
                    : m_pFunBase(new MemberFunction0<R, T>(pObj, pMemFun))
                {

                }

                ~Function()
                {
                    delete m_pFunBase;
                }

                R operator ()()
                {
                    return m_pFunBase->Invoke();
                }

            private:
                FunctionBase0<R> *m_pFunBase;
            };

            如果對(duì)上面說(shuō)的“普通函數(shù)的使用方式必須是函數(shù)指針而不是函數(shù)本身”耿耿于懷,可以再引入一個(gè)的構(gòu)造函數(shù):

            typedef R (FunctionType)();

            Function(const FunctionType &fun)
                : m_pFunBase(new Function0<R, FunctionType &>(fun))
            {

            }

            這里 FunctionType 是 R(&)() 類(lèi)型,強(qiáng)制使用它來(lái)特化 Function0 中的 T。該構(gòu)造函數(shù)在重載決議中會(huì)取得優(yōu)先權(quán)從而使普通函數(shù)本身的傳入成為可能。不過(guò),以函數(shù)本身形式傳入的普通函數(shù)會(huì)喪失一些特性,比如 Function<int()> 只能接受 int() 類(lèi)型的普通函數(shù)而不能接受 char () 型的普通函數(shù),因?yàn)檫@種情況下不會(huì)走我們剛才新定義的構(gòu)造函數(shù)。

            還有一種做法,就是針對(duì)全局函數(shù),強(qiáng)制特化出模版參數(shù)為其引用類(lèi)型的類(lèi)。定義如下元函數(shù):

            template <typename Signature>
            struct FunctionTraits
            {
                typedef Signature ParamType;
            };
               
            template <typename RetType>
            struct FunctionTraits<RetType ()>
            {
                typedef RetType (&ParamType)();
            };

            然后構(gòu)造函數(shù)改為:

                template <typename T>
                Function(const T &fun)
                    : m_pFunBase(new Function0<R, typename FunctionTraits<T>::ParamType>(fun))
                {
                   
                }

            用以上方法,所有的特性都不會(huì)丟失。

            到這兒,我們的 Function 已經(jīng)可以小試牛刀了:

            Function<int ()> f1(&intfun0);

            Function<int ()> f1_(intfun0);
            Function<int ()> f2(intfunctor0);
            Function<int ()> f3(&test, &Test::intmem0);

            f1();
            f1_();
            f2();
            f3();

            上面這段代碼已經(jīng)能夠正常運(yùn)行了。

            來(lái),繼續(xù)做一個(gè),送一個(gè)。下面的代碼居然也能跑(voidfun0、voidfunctor0、Test::voidmem0類(lèi)似int版本定義):

            Function<void ()> f4(&voidfun0);
            Function<void ()> f4_(voidfun0);
            Function<void ()> f5(voidfunctor0);
            Function<void ()> f6(&test, &Test::voidmem0);

            f4();
            f4_();
            f5();
            f6();

            這說(shuō)明了,在類(lèi)里面寫(xiě)一個(gè)返回值為該類(lèi)型的函數(shù),并在里面寫(xiě)下 return XXX; 然后以 void 為模版參數(shù)傳入該模版類(lèi),是符合語(yǔ)法的。驗(yàn)證一下:

            template <typename T>
            class Foo
            {
            public:
                T Bar()
                {
                    printf("%s invoked\n", __FUNCTION__);
                    return T();
                }
            };

            int main()
            {
                Foo<void> f1;
                f1.Bar();

                Foo<int> f2;
                int i = f2.Bar();

                return 0;
            }

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

            Foo<void>::Bar invoked
            Foo<int>::Bar invoked

            到此為止,我們已經(jīng)實(shí)現(xiàn)了 0 個(gè)參數(shù)的函數(shù)支持,也即 R () 類(lèi)型的所有函數(shù)的支持。接下來(lái)還要實(shí)現(xiàn)對(duì)具有 1 個(gè)、2 個(gè)、3 個(gè)直至任意有限個(gè)參數(shù)的函數(shù)支持。也許您也發(fā)現(xiàn)了,接下來(lái)的工作可以是體力活,我們可以照葫蘆畫(huà)瓢,搞出一堆 FunctionBaseN、FunctionN、MemberFunctionN,并在最后的 Function 中再實(shí)現(xiàn) N 個(gè)偏特化版本。是,不錯(cuò),大致上原理就是這樣。限于篇幅,我想暫時(shí)寫(xiě)到這里,下篇將繼續(xù)談?wù)労辍ypeList,以及怎樣少花點(diǎn)力氣實(shí)現(xiàn)其余 N 個(gè)版本。最終達(dá)到的效果是,只要改一個(gè)宏定義,就可以提高參數(shù)上限。

            在本文所涉及的內(nèi)容中,我比較糾結(jié)的是,可否在不用多態(tài)機(jī)制的情況下達(dá)到比較優(yōu)雅的形式統(tǒng)一?

            歡迎討論。

            posted @ 2011-01-16 22:17 溪流 閱讀(7313) | 評(píng)論 (55)編輯 收藏

            事情的緣起是,耐不住寂寞,準(zhǔn)備開(kāi)始造GUI的輪子。

            GUI框架,要做的事情我想大概是這么幾步:

            1. 實(shí)現(xiàn)回調(diào)函數(shù)的成員化。
            2. 實(shí)現(xiàn)方便程度可接受的消息映射。
            3. 確定上述核心部件的使用方式。
            4. 制造大量的控件。

            前三步要走的比較小心,第四步是體力勞動(dòng)。

            第一步,Windows下可參考的是MFC方式、WTL方式,以及利用Window相關(guān)屬性中的某些空位。前不久剛初步看過(guò)WTL的機(jī)制,雖然當(dāng)時(shí)沒(méi)寫(xiě)GUI框架的打算,不過(guò)也有點(diǎn)技術(shù)準(zhǔn)備的意思了。現(xiàn)學(xué)現(xiàn)用吧。這里一個(gè)可以預(yù)見(jiàn)的問(wèn)題是64位兼容,現(xiàn)在沒(méi)有測(cè)試環(huán)境,先不管。

            接下來(lái)看第二步了,所要做的事情就是把 WndProc 下的 一堆 case 有效地組織起來(lái),或者換個(gè)寫(xiě)法。之前還真不知道 MFC/WTL 的 BEGIN_MSG_MAP。以為很高深的,想不到就是拼裝成一個(gè)大的 WndProc。先抄了,做成一個(gè)可運(yùn)行的版本。但是,這方面會(huì)直接決定以后的大部分使用方式,單單抄一下意義不大。后來(lái)去 @OwnWaterloo 曾推薦過(guò)的 @cexer 的博客上逛了幾圈,第一圈看了一些描述性文字,第二圈大概看了下技術(shù),第三圈是挖墳,那個(gè)傳說(shuō)中的 cppblog 第一高樓啊。。其中有一個(gè)使用方式很新穎,嗯……是那個(gè)不需要手動(dòng)寫(xiě)映射代碼,直接實(shí)現(xiàn)消息處理函數(shù)的方式。不過(guò)我后來(lái)覺(jué)得還是不要這種樣子了,憑我個(gè)人的直覺(jué),如果我寫(xiě)下這樣的處理函數(shù),我大概會(huì)因?yàn)椴恢篮螘r(shí)注冊(cè)了這個(gè)函數(shù)而找不到調(diào)用來(lái)源而感到郁悶。在Windows回調(diào)機(jī)制的影響下,我可能會(huì)很抱有偏見(jiàn)地認(rèn)為,只有直接來(lái)自WndProc的調(diào)用,才算是來(lái)源明確的,不需要繼續(xù)追蹤的——當(dāng)然,這是建立在我不熟悉這個(gè)框架的基礎(chǔ)上的。框架必然需要隱藏調(diào)用來(lái)源,以及其他一些細(xì)節(jié),但是在這一步,我覺(jué)得稍微有點(diǎn)早。

            剛才說(shuō)到的都是靜態(tài)綁定。現(xiàn)在我有點(diǎn)傾向于動(dòng)態(tài)綁定。從使用方便程度上來(lái)看,動(dòng)態(tài)綁定更具靈活性。從性能上,動(dòng)態(tài)綁定下,消息到處理函數(shù)的查找過(guò)程可以更快,靜態(tài)綁定只能遍歷。當(dāng)然,未必將“添加處理函數(shù)”這樣的接口提供給最終用戶(hù),但是這個(gè)操作對(duì)于整個(gè)控件體系的形成應(yīng)該蠻有幫助的吧。比如MFC下一個(gè)控件類(lèi)使用Message Map做了一些事情,繼承類(lèi)就無(wú)法直接繼承這個(gè)動(dòng)作,于是可能需要做兩套處理函數(shù)調(diào)用機(jī)制,一套是給內(nèi)部繼承用的,一套是給用戶(hù)的。如果在最開(kāi)始的基類(lèi)保存一個(gè)消息映射,每個(gè)消息對(duì)應(yīng)一族處理函數(shù),每個(gè)繼承類(lèi)都可以添加處理函數(shù),但不刪除父類(lèi)已添加的函數(shù),這樣就可以在一套Message Map機(jī)制下獲得父類(lèi)的行為。以上,不知道考慮得對(duì)不對(duì),歡迎討論。

            其中,父類(lèi)保存子類(lèi)給出的可調(diào)用體并正確執(zhí)行是個(gè)問(wèn)題。折騰了一些時(shí)間,都沒(méi)有成功。我比較糾結(jié),想知道除了用function之類(lèi)的玩意兒外還有沒(méi)有其他簡(jiǎn)單可行的辦法。后來(lái)去@zblc的群上問(wèn),@vczh也說(shuō)需要一套function機(jī)制。看來(lái)是逃不開(kāi)這個(gè)問(wèn)題了。嗯……想起來(lái)大約兩個(gè)月前一個(gè)同事從codeproject找來(lái)了一個(gè)GUI框架看,看到幾行整整齊齊的 AddMsgHandler(WM_CREATE, XXX(this, &MyWindow::OnCreate));,嘆不已。我當(dāng)時(shí)打趣說(shuō),這很簡(jiǎn)單的,無(wú)非是搞了個(gè) function 而已,哥哥兩天就能搞定。于是他們叫我兩天搞定。我鼓搗了10分鐘,搞不定,只好丟一句,真的很簡(jiǎn)單的,類(lèi)似boost::function,你去看一下就知道了,哥哥要干活了。

            既然現(xiàn)在還是繞不開(kāi)這個(gè)問(wèn)題,那還是搞一下了,搞好以后就權(quán)且當(dāng)做給他們交作業(yè)吧。我會(huì)另寫(xiě)一篇文章說(shuō)說(shuō)function的事情,這里先略過(guò)。現(xiàn)在開(kāi)始假設(shè)這個(gè)設(shè)施已經(jīng)造好了。那么,窗口類(lèi)中大概可以這么定義相關(guān)類(lèi)型:

            typedef Function<bool (WPARAM, LPARAM)> MsgHandler;
            typedef List<MsgHandler> MsgHandlerList;
            typedef Map<UINT, MsgHandlerList> MsgMap;

            然后再定義一個(gè)變量:

            MsgMap  m_MsgMap;

            它用于保存消息映射。最終的回調(diào)函數(shù)可以寫(xiě)成:

            LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
            {
                bool bHandled = false;

                MsgMap::Iterator itMsgMap = m_MsgMap.Find(uMsg);

                if (itMsgMap != m_MsgMap.End())
                {
                    for (MsgHandlerList::Iterator it = itMsgMap->Value.Begin();
                         !bHandled && it != itMsgMap->Value.End(); ++it)
                    {
                        bHandled = (*it)(wParam, lParam);
                    }
                }

                return bHandled ? TRUE : DefWindowProc(m_hWnd, uMsg, wParam, lParam);
            }

            最后給個(gè)添加消息映射的接口:

            void AppendMsgHandler(UINT uMsg, MsgHandler pMsgHandler)
            {
                m_MsgMap[uMsg].PushBack(pMsgHandler);
            }

            到目前為止,我們的窗口類(lèi)大致上可以寫(xiě)成這樣:

            #include <Windows.h>
            #include <tchar.h>
            #include "../GUIFramework/xlWindowBase.h"

            class Window : public xl::WindowBase
            {
            public:
                Window()
                {
                    AppendMsgHandler(WM_ERASEBKGND, MsgHandler(this, &Window::OnEraseBackground));
                    AppendMsgHandler(WM_PAINT,      MsgHandler(this, &Window::OnPaint));
                    AppendMsgHandler(WM_LBUTTONUP,  MsgHandler(this, &Window::OnLButtonUp));
                    AppendMsgHandler(WM_RBUTTONUP,  MsgHandler(this, &Window::OnRButtonUp));
                    AppendMsgHandler(WM_DESTROY,    MsgHandler(this, &Window::OnDestroy));
                }

            protected:
                bool OnEraseBackground(WPARAM wParam, LPARAM lParam)
                {
                    return false;
                }

                bool OnPaint(WPARAM wParam, LPARAM lParam)
                {
                    PAINTSTRUCT ps = {};
                    BeginPaint(m_hWnd, &ps);

                    RECT rect = { 200, 200, 400, 400 };
                    DrawText(ps.hdc, _T("Hello, world!"), -1, &rect, DT_CENTER | DT_VCENTER);

                    EndPaint(m_hWnd, &ps);
                    return false;
                }

                bool OnLButtonUp(WPARAM wParam, LPARAM lParam)
                {
                    MessageBox(m_hWnd, _T("LButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);
                    return false;
                }

                bool OnRButtonUp(WPARAM wParam, LPARAM lParam)
                {
                    MessageBox(m_hWnd, _T("RButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);
                    return false;
                }

                bool OnDestroy(WPARAM wParam, LPARAM lParam)
                {
                    PostQuitMessage(0);
                    return false;
                }
            };

            在最基礎(chǔ)的 WindowBase 里,搞成這樣大概差不是很多了。暫時(shí)先看第三步。到目前為止,我所聽(tīng)說(shuō)過(guò)的 GUI 框架都是真正的框架,似乎沒(méi)有“GUI 庫(kù)”。為什么一定要以繼承某個(gè)基類(lèi)的方式來(lái)使用呢?如果像下面這樣使用呢?

            class Window
            {
            private:
                xl::WindowBase m_WindowBase;

            public:
                Window()
                {
                    m_WindowBase.AppendMsgHandler(WM_ERASEBKGND, MsgHandler(this, &Window::OnEraseBackground));
                    m_WindowBase.AppendMsgHandler(WM_PAINT,      MsgHandler(this, &Window::OnPaint));
                    m_WindowBase.AppendMsgHandler(WM_LBUTTONUP,  MsgHandler(this, &Window::OnLButtonUp));
                    m_WindowBase.AppendMsgHandler(WM_RBUTTONUP,  MsgHandler(this, &Window::OnRButtonUp));
                    m_WindowBase.AppendMsgHandler(WM_DESTROY,    MsgHandler(this, &Window::OnDestroy));
                }
            };

            這個(gè)問(wèn)題,不知道各位有沒(méi)有什么思考?

            還有一個(gè)問(wèn)題是,接下去要不要將 WPARAM 和 LPARAM 的含義徹底解析掉,搞成一系列 PaintParam、EraseBackgroundParam、LButtonUpParam、RButtonUpParam,DestroyParam,讓使用的時(shí)候與原始消息參數(shù)徹底隔離呢?

            最后一步,雖說(shuō)是體力活,但這跟最終的應(yīng)用場(chǎng)合密切相關(guān),需要提供怎么樣的功能是一件需要考量的事。

            目前走在第二步,所以下面的兩個(gè)問(wèn)題思考得不多。求經(jīng)驗(yàn),求意見(jiàn)。

            posted @ 2011-01-16 20:05 溪流 閱讀(4203) | 評(píng)論 (11)編輯 收藏
            僅列出標(biāo)題
            共18頁(yè): First 6 7 8 9 10 11 12 13 14 Last 
            午夜不卡888久久| 久久久国产打桩机| 99久久精品国产综合一区| 91精品无码久久久久久五月天| 91精品国产91久久久久久蜜臀| 久久精品成人一区二区三区| 一本色道久久综合狠狠躁篇| 久久久久99精品成人片欧美| 久久成人国产精品一区二区| 婷婷久久精品国产| 综合久久国产九一剧情麻豆| 久久久久四虎国产精品| 一级做a爰片久久毛片看看| 国内精品久久久久影院日本| 色8激情欧美成人久久综合电| 国产99久久精品一区二区| 久久人妻少妇嫩草AV蜜桃| 国内精品久久久久影院日本| 伊人久久大香线蕉成人| 91亚洲国产成人久久精品| 人妻精品久久久久中文字幕69| 91久久精品无码一区二区毛片| 日产精品久久久久久久| 亚洲美日韩Av中文字幕无码久久久妻妇 | 久久久久久曰本AV免费免费| 国内精品久久九九国产精品| 777午夜精品久久av蜜臀| 香蕉aa三级久久毛片| 国产高清美女一级a毛片久久w| 国产精品久久久久影院色| 色婷婷久久综合中文久久蜜桃av| 2021国内精品久久久久久影院| 香港aa三级久久三级| 久久精品国产久精国产思思 | 亚洲欧美精品伊人久久| 久久发布国产伦子伦精品| 午夜久久久久久禁播电影| 亚洲国产视频久久| 精品久久久无码21p发布| 国内精品综合久久久40p| 日韩AV无码久久一区二区|