• <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  評論-947  文章-0  trackbacks-0
             

            目錄:

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

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

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

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

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

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

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

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

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

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

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

            [未完待續(xù)]

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

            目錄:

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

            2009年3月2日,是我上班的第一天。不過這時候還不叫正式工作,稱為實習。公司方面說因為畢業(yè)證沒拿到無法簽訂勞動合同。我要承受的代價就是50%工資。不過對于當時還沒有嘗過親手賺錢的滋味的我來說,50%也已經相當豐厚了,至少這個學期吃飯問題可以自己解決了。

            上班第一天,考研成績出來了,我跟預料的一樣,沒考上:

            B1E9144DD8637DFA_163_0

            唯一可以得瑟的是,政治果然靠覺悟啊,我比參加了好些時日培訓班的同學們也少不了幾分;其余的不堪入目,就不多說了,丟臉,還復習過三天呢,沒復習過還可以說說。

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

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

            我在跨國公司的第一任主管是L1姐,一個年輕的媽媽,在她身上洋溢著母愛。有時候晚上加班,聽她給沒幾歲的孩子解釋不能回去的理由,以及那種認真勁兒、那種語氣,就能感知到她是沉浸在怎樣的幸福中。不過L1在工作上的態(tài)度還是蠻嚴肅認真的。在上班的第二個星期,我就參與了實際項目,而且是個新小項目。這種機會蠻難得的。在L1的指導和要求下,我覺得我那時起才開始有了一點點設計理念。為了得到她的肯定,我會盡量將代碼組織得漂亮點。之后不久我又被安排同時參與另一個項目的維護工作。看過現(xiàn)有代碼,才感覺到大家寫的代碼原來是這樣的糟糕。不太客氣地說,80%以上的代碼是沒有經過好好組織的,90%以上的代碼的書寫是不工整的,以至于當時在手的那個新項目看上去爽多了。大概那時侯起,我覺察到老項目與新項目的截然不同的面貌,心里帶上了一些疑問:是否老項目一開始也是很漂亮的呢?是否漂亮的新項目過些時日也會變得面目不堪呢?

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

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

            說起加班,不得不再說幾句。到目前為止,我都認為L1是跨國公司里對項目進度控制的最好的一個主管,時間觀念很強。在我忘記或者即將忘記時間的時候,總是能得到善意提醒。所以她帶的項目極少加班,需求也被整理的有條不紊,每周都知道要干什么,每天都直到要干什么,即使加班,也知道因何事而加,知道做完什么以后就能離開。

            雖然屬于實習,但是3月份是我這份工作中過的最開心的一段日子,也是成長蠻快的一段日子。在這里要衷心的謝謝L1在那段時期以及日后的很多日子里給予的指點、幫助,以及關心。

            [未完待續(xù)]

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

            目錄:

            C++ 下 Function 對象的實現(xiàn)(上)
            C++ 下 Function 對象的實現(xiàn)(下)

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

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

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

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

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

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

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

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

            實現(xiàn)兩個版本,分別支持非成員函數(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;
            };

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

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

            增加一個 Function 類的偏特化版本:

            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)在,我們可以跑一下測試代碼了:

            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);

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

            觀察上面的這些代碼,和我們在上一篇中的代碼高度一致,不同的是那些模版參數(shù)、偏特化參數(shù)、函數(shù)調用參數(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

            那么我們可以使用一個 n 就寫出支持所有具有參數(shù)的函數(shù)的 Function 了。我們拋棄掉上面的 1 系列的所有類,僅保持上篇留下來的代碼,然后利用上面 4 個宏將所有數(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;
            };

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

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

            暴力點,我們可以這樣:

            #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

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

            #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)

            這個 TYPENAME_LIST 就是符合上文要求的宏。接下來如法炮制其余三個:

            #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)

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

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

            上面的 REP 不會被繼續(xù)展開了。

            為此,一個不太聰明的辦法就是,再定義一組 REP2。嗯,是個辦法,就這么辦吧。另外我們剛才的 REP 系列沒有將分隔符作為參數(shù),默認使用逗號,而最后一不的 FUNCTION_IMPLEMENT 的重復中是不能用逗號的。考慮提取出來作為參數(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 個參數(shù)了。為了支持更多參數(shù),把上面的 REP 以及 REP2 系列多定義一點,比如到 50,那么 FUNCTION_IMPLEMENT 的括號中就可以填 50 以內的任意數(shù)了。考慮到宏展開對編譯速度的影響,以及實際應用中函數(shù)參數(shù)的個數(shù),定為 20 左右比較合適。

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

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

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

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

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

            目錄:

            C++ 下 Function 對象的實現(xiàn)(上)
            C++ 下 Function 對象的實現(xiàn)(下)

            起因在上一篇已經說過了。現(xiàn)在讓我們直接進入主題。本文的目標是,讓以下代碼能順利跑起來:

            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ù)和沒返回值的函數(shù),以及有0個、1個、2個、……、MAX 個參數(shù)的函數(shù),參數(shù)類型無限制。最后實現(xiàn)的 Function 對象僅僅可以執(zhí)行就好。(至于是否可拷貝、是否可判斷相等 等問題,都是小事,本文暫不考慮。)最后,Bind 概念也不在本文討論范圍之內。

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

            先定義一個虛基類:

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

            然后實現(xiàn)一個普通函數(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;
            };

            這里需要說明的是,如果是普通函數(shù),T會被特化成 R() 或者 R (&)() 或者 R(*)(),取決于使用的時候傳入 fun 還是傳入 &fun。所以不必另外實現(xiàn)針對 R(*)() 的版本。Loki (姑且就以作品名稱乎 Loki 的作者吧,他那個真名實在是太長)在他的書中稱之為“做一個,送一個”。不過對于他書中所說的,我有一個疑惑。Loki 說傳入 fun,模版參數(shù) T 會被特化成 R (&)(),于是一切順利。可是我在操作過程中發(fā)現(xiàn) T 一直被特化成 R (),于是上述 class 中的 m_Fun 被認為是成員函數(shù)而不是成員變量。不知道是為什么,有知道者請不吝指教哈。因為以上原因,本文中我一直用 &fun 的形式對待普通函數(shù)。

            再實現(xiàn)一個成員函數(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;
            };

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

            為了達到這個目標,我們要玩一些偏特化技巧。關于偏特化,我一直以來的膚淺認識都是錯誤的。我原以為,對于模版類:

            template <typename T0, typename T1>
            class Foo;

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

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

            }

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

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

            }

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

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

            }

            以及

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

            }

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

            回到我們剛才的主題,我們要提供給用戶的是這樣一個類:

            template <typename Signature>
            class Function;

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

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

            這里使用 R () 特化原始的 Signature,引入一個新的參數(shù) R。于是返回值類型 R 就被萃取出來了。實現(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;
            };

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

            typedef R (FunctionType)();

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

            }

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

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

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

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

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

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

            到這兒,我們的 Function 已經可以小試牛刀了:

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

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

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

            上面這段代碼已經能夠正常運行了。

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

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

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

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

            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;
            }

            運行結果:

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

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

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

            歡迎討論。

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

            事情的緣起是,耐不住寂寞,準備開始造GUI的輪子。

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

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

            前三步要走的比較小心,第四步是體力勞動。

            第一步,Windows下可參考的是MFC方式、WTL方式,以及利用Window相關屬性中的某些空位。前不久剛初步看過WTL的機制,雖然當時沒寫GUI框架的打算,不過也有點技術準備的意思了。現(xiàn)學現(xiàn)用吧。這里一個可以預見的問題是64位兼容,現(xiàn)在沒有測試環(huán)境,先不管。

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

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

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

            既然現(xiàn)在還是繞不開這個問題,那還是搞一下了,搞好以后就權且當做給他們交作業(yè)吧。我會另寫一篇文章說說function的事情,這里先略過。現(xiàn)在開始假設這個設施已經造好了。那么,窗口類中大概可以這么定義相關類型:

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

            然后再定義一個變量:

            MsgMap  m_MsgMap;

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

            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);
            }

            最后給個添加消息映射的接口:

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

            到目前為止,我們的窗口類大致上可以寫成這樣:

            #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;
                }
            };

            在最基礎的 WindowBase 里,搞成這樣大概差不是很多了。暫時先看第三步。到目前為止,我所聽說過的 GUI 框架都是真正的框架,似乎沒有“GUI 庫”。為什么一定要以繼承某個基類的方式來使用呢?如果像下面這樣使用呢?

            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));
                }
            };

            這個問題,不知道各位有沒有什么思考?

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

            最后一步,雖說是體力活,但這跟最終的應用場合密切相關,需要提供怎么樣的功能是一件需要考量的事。

            目前走在第二步,所以下面的兩個問題思考得不多。求經驗,求意見。

            posted @ 2011-01-16 20:05 溪流 閱讀(4194) | 評論 (11)編輯 收藏
            僅列出標題
            共18頁: First 6 7 8 9 10 11 12 13 14 Last 
            国产69精品久久久久观看软件| 国产精品成人精品久久久| 国产精品久久新婚兰兰| 人人狠狠综合久久88成人| 精品久久久久久久无码 | 精品伊人久久久| 亚洲AV无一区二区三区久久| 国产精品久久久久9999| 色悠久久久久久久综合网| 久久人人爽人人爽人人片AV不| 亚洲国产二区三区久久| 日日躁夜夜躁狠狠久久AV| 精品久久久久久久久久中文字幕| 老男人久久青草av高清| 91久久精品国产成人久久| 色欲综合久久中文字幕网| 久久综合狠狠综合久久97色| 国产一区二区三区久久精品| 囯产精品久久久久久久久蜜桃| 91久久九九无码成人网站| 国内精品久久久久久99蜜桃| 国产精品久久久香蕉| 91久久精品国产91性色也| 久久精品亚洲精品国产色婷| 77777亚洲午夜久久多人| 久久这里有精品| 精品国产日韩久久亚洲| 人妻丰满?V无码久久不卡| 国产亚州精品女人久久久久久| 久久成人影院精品777| 久久精品天天中文字幕人妻 | 久久婷婷久久一区二区三区| 欧美熟妇另类久久久久久不卡| 亚洲综合久久久| 亚洲综合伊人久久大杳蕉| 无码人妻久久一区二区三区蜜桃| 一本久久免费视频| 狠狠综合久久AV一区二区三区| 少妇无套内谢久久久久| 久久综合给合久久国产免费| 精品久久久久久成人AV|