• <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>

            woaidongmao

            文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數(shù)據(jù)加載中……

            VC++ 6.0的小花招

            Visual Studio系列中產(chǎn)品中,Visual Studio 6.0是最經(jīng)典的一個版本,雖然后來有Visual Studio .NET 2003,以及2005,也確實(shí)添加了很多讓我覺得激動的特性,但是從使用細(xì)節(jié)的細(xì)膩程度上來看,VS 6.0無疑是最棒的。我們一些同事甚至試圖把2005C++編譯器獨(dú)立的拿到Visual Studio 6.0中來用,也不愿意升級到.NET上來用,可見其魅力。

             

            VS 6.0這個產(chǎn)品的成熟相比,VC++ 6.0的編譯器的的確確相對來說有些糟糕,其中最被詬病的是對模板技術(shù)支持很不好。下面我想做的一件事情,就是向那些繼續(xù)留戀VC++ 6.0的朋友,介紹一些小花招,來避開VC++ 6.0的一些編譯器缺陷。

             

             

            1for (type var=expression;;) 中變量var的作用域問題。

             

            按照C++標(biāo)準(zhǔn),這里定義的變量var出了for循環(huán)應(yīng)該被銷毀。也就是說下面這段代碼是有效的:

             

               for (int i = 0; i < 100; ++i)

                   func();

               for (int i = 0; i < 100; ++i)

                   func2();

             

            而下面這段代碼應(yīng)該編譯不過:

             

                for (int i = 0; i < 100; ++i)

                {

                     if (has_found_it())

                     {

                         handle_find_result();

                         break;

                      }

                }

                if (i == 100)

                     do_not_found();

             

            然而VC++ 6.0對于第一段代碼會報變量i重復(fù)定義錯誤,而第二段代碼編譯通過。

             

            為了讓VC++ 6.0for語句看起來符合C++標(biāo)準(zhǔn),你可以這樣做:

             

               #define for if (0); else for

             

            你會發(fā)現(xiàn)很有趣,這樣define一下后,VC++ 6.0for語句完全符合C++標(biāo)準(zhǔn)了!而且由于編譯器的優(yōu)化,Release版本不會增加任何額外的開銷。

             

            喜歡鉆牛角尖的朋友可能會說:嗯,不錯的主意。但是——為什么不這樣做:

             

               #define for if (1) for

             

            嗯?看起來也可以。還是讓我們看一個用例:

             

               if (cond)

                  for (int i = 0; i < 100; ++i)

                      func1();

               else

                   func2();

             

            進(jìn)行宏代碼展開后,成為:

             

               if (cond)

                   if (1)

                       for (int i = 0; i < 100; ++i)

                           func1();

                   else

                       func2();

             

            這個結(jié)果顯然不能符合我們的原意。這里func2();語句永遠(yuǎn)得不到執(zhí)行機(jī)會。

             

             

            2)模板參數(shù)類型如果不出現(xiàn)在參數(shù)列表中,則不能作為返回值類型。

             

            由于編譯器的缺陷,VC++ 6.0不支持以下這種用法:

             

               template <class T1, class T2>

               T1 func(T2 arg)

               {

                   T1 var;

                   ... // 處理var過程

                   return var;

               }

             

               void test()

               {

                   int result1 = func<int>(1);

                   double result2 = func<double>(2);

               };

             

            很抱歉,這種用法VC++ 6.0不支持。讓人惱火的是,VC++ 6.0編譯時不會提示錯誤,但是生成的執(zhí)行代碼卻很成問題。

             

            究其原因,是因?yàn)?span lang="EN-US">VC++ 6.0template技術(shù)是在編譯器的較高層次做的,真正的編譯器核心并不考慮模板。以上面的代碼為例,對編譯器核心來說,只是有兩個重載函數(shù)而已:

             

               int func(int arg);

               double func(int arg);

             

            如果是普通情況,只是返回值不同的函數(shù),是不能同時存在的,編譯器應(yīng)該認(rèn)為這是一個錯誤。但是很在模板情況下,這兩個函數(shù)被簡單認(rèn)為是同一個函數(shù)。因?yàn)?span lang="EN-US">VC++ 6.0會為每個函數(shù)根據(jù)它的:

               1)所在的namespace

               2)所在的類的類名(如果是成員函數(shù));

               3)函數(shù)名;

               4)函數(shù)調(diào)用方式(cdeclstdcall還是fastcall);

               5)所有參數(shù)的類型;

            而生成一個唯一標(biāo)識該函數(shù)的函數(shù)名。這個過程叫Name Mangling,是所有C++編譯器都要進(jìn)行的工作。而另一個背景是,很多C++編譯器生成的目標(biāo)文件(.obj文件)有一些和模板相關(guān)的特殊信息,包括也標(biāo)識了某個函數(shù)是否模板函數(shù)。這是因?yàn)橐粋€模板函數(shù)在多個源文件(.cpp文件)中被調(diào)用的話,這個模板函數(shù)就會在這些源文件編譯生成的目標(biāo)文件(.obj文件)中都定義(definition)一份。為了支持模板,link程序顯然必須知道這個函數(shù)是模板函數(shù),從而隨意選擇一個定義(丟棄其余的定義),而不是報符號重復(fù)定義錯誤。

             

            因?yàn)楹瘮?shù)名、參數(shù)列表等完全一致,所以這兩個函數(shù)Name Mangling后生成的名字是一樣的,并且,它們都被標(biāo)識為這是模板函數(shù)。從而,link程序在工作的時候,簡單地將其中一個函數(shù)定義給拋棄了。

             

            那么,如果我們非要提供上述的func函數(shù),怎么辦?我們來點(diǎn)花招:

             

            template <class T1>

            class func

            {

            private:

                T1 var;

             

            public:

                template <class T2>

                func(T2 arg)

                {

                   ... // 處理var過程

                }

                operator T1() const

                {

                    return var;

                }

            };

             

            我們再來使用func這個函數(shù)

             

               void test()

               {

                   int result1 = func<int>(1);

                   double result2 = func<double>(2);

               };

             

            呵呵,你會發(fā)現(xiàn),它還真象是你期望的正常工作。

             

             

            3)仿真VC++提供的關(guān)鍵字__uuidof

             

            這個技巧不是針對VC++ 6.0缺陷的,而是針對VC++擴(kuò)展語法的。這個技巧的來由,是為了某些希望有一天有可能要脫離Visual C++環(huán)境進(jìn)行開發(fā)的人員。為了脫離VC++,你需要謹(jǐn)慎使用它的所有擴(kuò)展語法。例如本文討論的__uuidof。我們先來看看一個例子:

             

            class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Class;

            struct __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BB")) Interface;

             

            void test()

            {

               CLSID clsid = __uuidof(Class);

               IID iid = __uuidof(Interface);

               ...

            }

             

            這比起你以前定義uuid的方法簡單多了吧?可惜,這樣好用的東西,它只在VC++中提供。不過沒有關(guān)系,我們這里介紹一個技巧,可以讓你在幾乎所有C++編譯器中都可以這樣方便的使用__uuidof。這里沒有說是所有,是因?yàn)槲覀兪褂昧四0逄鼗夹g(shù),可能存在一些比較古老C++編譯器,不支持該特性。

             

            也許你已經(jīng)迫不及待了。好,讓我們來看看:

             

            #include <string>

            #include <cassert>

             

            inline

            STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz)

            {

                HRESULT hr;

                GUID guid;

                if (lpsz[0] == '{')

                {

                    hr = CLSIDFromString(lpsz, &guid);

                }

                else

                {

                    std::basic_string<OLECHAR> strGuid;

                    strGuid.append(1, '{');

                    strGuid.append(lpsz);

                    strGuid.append(1, '}');

                    hr = CLSIDFromString((LPOLESTR)strGuid.c_str(), &guid);

                }

                assert(hr == S_OK);

                return guid;

            }

             

            template <class Class>

            struct _UuidTraits {

            };

             

            #define _DEFINE_UUID(Class, uuid)                                        \

            template <>                                                              \

            struct _UuidTraits<Class> {                                              \

                static const GUID& Guid() {                                          \

                    static GUID guid = GUIDFromString(L ## uuid);                    \

                    return guid;                                                     \

                }                                                                    \

            }

             

            #define __uuidof(Class)    _UuidTraits<Class>::Guid()

             

            #define DEFINE_CLSID(Class, guid)                                        \

                class Class;                                                         \

                _DEFINE_UUID(Class, guid)

             

            #define DEFINE_IID(Interface, iid)                                       \

                struct Interface;                                                    \

                _DEFINE_UUID(Interface, iid)

             

             

            這樣一來,就已經(jīng)模擬出一個__uuidof關(guān)鍵字。我們可以很方便進(jìn)行uuid的定義。舉例如下:

             

            DEFINE_CLSID(Class, "{B372C9F6-1959-4650-960D-73F20CD479BA}");

            DEFINE_IID(Interface, "{B372C9F6-1959-4650-960D-73F20CD479BB}");

             

            void test()

            {

               CLSID clsid = __uuidof(Class);

               IID iid = __uuidof(Interface);

               ...

            }

             

            VC++中,為了與其他編譯器以相同的方式來進(jìn)行uuid的定義,我們不直接使用__declspec(uuid),而是也定義DEFINE_CLSID, DEFINE_IID宏:

             

            #define DEFINE_CLSID(Class, clsid)           \

                class __declspec(uuid(clsid)) Class

             

            #define DEFINE_IID(Interface, iid)           \

                struct __declspec(uuid(iid)) Interface

             

            這樣一來,我們已經(jīng)在所有包含VC++在內(nèi)的支持模板特化技術(shù)的編譯器中,提供了__uuidof關(guān)鍵字。通過它可以進(jìn)一步簡化你在C++語言中實(shí)現(xiàn)COM組件的代價。

             

            附注:關(guān)于本文使用的C++模板的特化技術(shù),詳細(xì)請參閱C++文法方面的書籍,例如《C++ Primer》。其實(shí)這個技巧在C++標(biāo)準(zhǔn)庫——STL中有一個專門的名字:traits(萃取),你可以在很多介紹STL的書籍中見到相關(guān)的介紹。

             

            posted on 2008-11-09 01:37 肥仔 閱讀(1339) 評論(0)  編輯 收藏 引用 所屬分類: VC 存檔C++ 模板

            久久亚洲国产精品成人AV秋霞| 久久精品aⅴ无码中文字字幕不卡| 亚洲国产高清精品线久久| 久久免费高清视频| 久久精品国产亚洲欧美| 情人伊人久久综合亚洲| 四虎影视久久久免费观看| 伊人色综合久久天天人手人婷| 亚洲AV无一区二区三区久久| 日本免费久久久久久久网站| 国产一区二区三精品久久久无广告| 人妻精品久久久久中文字幕| 无码国产69精品久久久久网站| a级毛片无码兔费真人久久| 久久人人超碰精品CAOPOREN| 国内精品人妻无码久久久影院| 国产无套内射久久久国产| 久久综合久久美利坚合众国| 久久国产乱子伦精品免费强| 亚洲精品视频久久久| 亚洲精品高清国产一久久| 亚洲αv久久久噜噜噜噜噜| 久久精品国产亚洲av瑜伽| 97久久超碰国产精品2021| 免费精品国产日韩热久久| 国产精品青草久久久久福利99| 亚洲AV日韩精品久久久久久| 欧美日韩精品久久久免费观看 | 狠狠色狠狠色综合久久| 久久久综合九色合综国产| 一本色道久久88精品综合| 麻豆久久| 国产午夜精品久久久久九九电影| 亚洲精品白浆高清久久久久久| 国产三级观看久久| 亚洲一区中文字幕久久| 久久久噜噜噜久久中文福利| 久久久久久久久久久精品尤物| 国产精品亚洲综合专区片高清久久久 | 伊人久久大香线蕉精品不卡 | 狠狠狠色丁香婷婷综合久久俺|