青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

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

枚舉聲明,模板函數特化

我很樂意解釋我是如何寫就 DumpEnum 的,甚至給出代碼。此間我還將回答第二個問題。不過首先讓我為其他讀者解釋一下 DumpEnum 是做什么的。在四月發表的文章中,我要做的一件事情是寫一個 C++ 枚舉來完全充當 .NET 框架類型 RegexOptionsRegexOptions 是一個枚舉類型,你可以用 Regex::Match Replace 之類的方法來控制匹配。例如,你可以用 RegexOptions::IgnoreCase 來調用 Regex::Match 以忽略大小寫,或者
RegexOptions::Singleline
來將輸入串作為一行。RegexOptions 的值如 Figure 1 所示。
  為了從本機C++代碼傳遞 RegexOptions,你需要一個具有相同值的 C-式樣枚舉。如果你僅僅是一時之需,那么編寫這樣的代碼最快的方法是從文檔中將之拷貝到你的 C++ 文件,然后按照 C 的語法編輯它。但如果你要進行印刷,或修改選項,或者想要包裝若干枚舉類型的話,那么最好最可靠的方法是寫一個工具,它能自動生成 C++ 代碼——尤其反射使之更容易;.NET 框架提供了全部描述自身所需的信息。所以我寫了一個小程序 DumpEnum,你可以從命令行運行它,像這樣:

DumpEnum RegexOptions

DumpEnum 將名字/值對寫成 C/C++ 代碼送到標準輸出。你可以像下面這樣將輸出重定向到一個文件:

DumpEnum RegexOptions > regopt.h

  然后將 regopt.h 插入到你的頭文件。在我的文章中,RegexWrap.h 就是這么做的。DumpEnum RegexOptions 實際生成的文件如 Figure 2 所示。
  現在你知道 DumpEnum 是做什么的了,下面你會明白我是如何實現它的。

  每一個框架類都是由 System.Type 類描述。它具備 Name 屬性以獲取類型名,IsEnum 告之該類型是否為枚舉。DumpEnum 要做的第一件事情是不論什么類型名,都要獲得 Type,把它們傳遞到命令行——例如,RegexOptions,實現它并不是想像的那么容易。獲得 Type 最普通的兩個方法是:如果已知對象實例,則調用 obj->GetType;否則用 __typeof。例如:

#using <System.dll>
using namespace System::Text::RegularExpressions;
...
Type *t = __typeof(RegexOptions);

  在 C++ 中使用托管類型必須用 __typeof,因為 typeof 已經有定義(在新的 C++\CLI 中要用 typeid<>)。但 __typeof 只能用于符號名,而不是字符串,這意味著編譯時你得知道名字,以及哪個程序集和其所屬的名字空間。DumpEnum 在編譯時不具備這些信息,所以要從命令行參數中獲得類型名。DumpEnum 也不具備對象實例,所以它無法調用 Object::GetType,怎么辦呢?
還有另一個得到 Type 的方法。如果已知該類型屬于哪個程序集,那么可以加載它并調用 Assembly::GetType,它有一個串參數。但 Assembly::GetType 需要完整的類型名,并且你得知道要加載哪個程序集。DumpEnum 給我的第一個痛是要我在命令行敲入下面這些信息:

DumpEnum System.dll System.Text.RegularExpressions.RegexOptions

  你知道 RegexOptions System.dll 中,而且你也知道名字空間是 System.Text.RegularExpressions,因為文檔就是這么說的。看文檔是一件很惱人的事,而且敲入這個完整的名字空間足以讓你得上腕關節綜合癥。我寧愿花三小時寫一個只需敲12個字符而不是54個字符的程序,而不原意花30秒鐘來查找DLL/namespace和敲入完整類型名。這似乎與懶惰者有些自相矛盾,但這是好程序員的精神特質所需要的,因為你最終是要做出一個很棒的工具永久使用——并且能夠與朋友們分享!
  在按照我的想法寫 DumpEnum 之前,必須解決幾個基本問題,其中包括本文的第二個提問:已知類型名(可能是非限定名),如:RegexOptions,如何知道哪個框架 DLL 包含該類型?沒有集中的數據庫或保存此信息的注冊表項(這也是一件好事情),或方法調用,看來是沒有希望了。但是等一等——再想想!所有的框架 DLLs 都在一個文件夾中,我最近一次數過也就七十來個。為什么強力使用之呢?只要將每個程序集加載到框架環境,查找到那個名字與期望的類型名匹配者。這樣很簡單直白,并且在我低檔的 1 GHz P3 上只需幾秒鐘。我寫了一個程序叫 FindType 就是做此事的:

FindType MenuItem

如圖 Figure 3 所示。FindType 列出所有名字中帶 MenuItem 類型輸出的框架 DLLsFindType 查找包含該單詞文本的類型。換句話說,如果你運行“FindType Control”,那么 FindType 將輸出 System.Windows.Forms.Control System.Web.UI.Control,但不包括 System.Web.UI.WebControls.WebControl。這個思路假設你輸入的是簡稱名字,也就是你在 #using 指令中使用的名字空間。FindType 通過建立“\bControl\b”這樣的正則表達式來實現。特殊的錨點字符(原子零寬度斷言)''\b''用于單詞分隔,而不用再匹配中包含分隔符。

clip_image001
Figure 3 FindType
的運行結果

FindType
是如何知道要搜索哪個 DLLs 呢?所有框架 DLLs 都在一個名叫“C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322”的文件夾中。你可以通過環境變量 %FrameworkDir% (實際解析出來是“C:\WINDOWS\Microsoft.NET\Framework”)和 %FrameworkVersion%“v1.1.4322”)來獲取自己機器上實際路徑。為了簡單起見,我在 CFindType 類中將此過程進行了封裝。為了使用這個類,你得派生自己專用的特例并實現虛擬函數 OnMatch

class CMyFindType : public CFindType {
protected:
   virtual BOOL OnMatch(LPCTSTR typName, LPCTSTR asmPath)
   {
      // print it
   }
};     

然后實例化并調用 FindExact 方法:

CMyFindType ft;
int nFound = ft.FindExact("MenuItem");

  CFindType 遍歷程序集,查找與傳入的名字相匹配的類型。只要找到一個匹配類型,便用該類型和程序集名調用你的虛擬 OnMatch 處理例程。如果你想用不同的正則表達式,你可以調用 CFindType::Find 代替 FindExactCFindType 類使 FindType 程序的實現變得容易:只要寫一個 OnMatch,將信息輸出到標準輸出 stdout 即可。具體細節請參考本文附帶的源代碼。
  CFindType 本身派生于一個更為一般的類,CEunmTypes,它枚舉框架中所有的類型,針對每個類型調用虛擬 OnType 函數。CFindType::OnType Regex 比較類型名和請求的名字,并調用 OnMarch 檢查其是否匹配。CEnumTypes _tgetenv 來獲得環境變量以建立型如“FrameworkDir\FrameworkVersion\*.dll”的文件規范,然后用 MFC CFileFind 類枚舉 DLLsCEunmTypes 試圖將每個 DLL 作為程序集加載。如果加載失敗(也許該 DLL 不是一個托管程序集),CEnumTypes 則忽略它并繼續搜索。如果加載成功,便調用 Assembly::GetExportedTypes 來獲取程序集輸出的 Type 數組,然后針對每個 Type 調用 OnType。代碼如 Figure 4 所示。
  現在有了 CFindType,我終于可以用它來解決最初的問題:修改 DumpEnum,以便我不用非得告訴它程序集和完整的類型名。DumpEnum 以不同的 OnMarch 處理例程使用 CFindTypeDumpEnum 中的處理例程檢查該類型確實在枚舉的類型中(Type::IsEnum 返回 True),如果真是如此,則按照 C++ 代碼方式取出枚舉名/值對,如果 Figure 2 所示。DumpIt 函數實際的工作內容如 Figure 5 所示。DumpIt Enum::GetUnderlyingType 獲取枚舉的底層類型(一般是 System.Int32),用 Enum::GetValues 獲取枚舉值,用 Convert::ChangeType 將枚舉值轉換為其對應的底層類型。以下是輸出顯示名字/值對的代碼:

Type* entype = // 托管枚舉類型
Array* values = Enum::GetValues(entype);
for (int i=0; iLength; i++) {
    Object* enval = values->GetValue(i);
    Object* unval = Convert::ChangeType(enval, untype);
    _tprintf(_T("\t%s = %s,\n"), enval, unval);
}

  現在你一舉兩得:FindType 使你能找到某個特定類型包含在哪個 DLL/程序集;DumpEnum 生成 C/C++ 代碼來包裝框架枚舉類型。
  繼續討論之前,本文有一個小插曲,我寫完 FindType 之后,發現一個令人沮喪的事情,在 Visual Studio .NET 中已經附帶有一個 FindType 程序,甚至名字都一樣!微軟版本的 FindType 所做的事情和我的相同,并且做得更好。(老天啊,微軟的老大們捷足先登;我暈倒!)
  微軟的 FindType 具備選項來指定完全或部分匹配要搜索的目錄和名字空間,是否顯示方法,屬性,事件等等。Figure 6 是它列出所有選項的幫助屏幕:

clip_image002
Figure 6 Visual Studio
附帶的 FindType

  如果你想了解更多關于反射,程序集和類型的內容,或者自在周五晚上無所事事,FindType 是個很好的學習研究例子。你可以在 VS.NET\SDK\v1.1\Samples\Applications\TypeFinder 目錄找到它的源碼,它是用 C# Visual Basic 寫的。我生成了 C# 版本,并將其 EXE 文件拷貝到我的 bin 目錄;現在我都是用 FindType 來查找類型的。
  是不是有了微軟的 FindType,我自己的版本就毫無用處了呢?當然不是。例如,CFindType CEnumTypes
是類,不是程序,也就是說你可以用它們來寫自己的查找類型信息的工具以及像 DumpEnum 這樣的程序。況且我的類是用中最好的編程語言 C++ 寫的。而微軟的版本用的則是 Visual Basic C#。如果你決定在自己打大應用程序中使用 CFindType,那么應該注意到 CFindType 不用在枚舉時考慮卸載程序集。因為每個程序集都會消耗相當多的內存,你可能會考慮修改這個實現,將每個程序集加載到其自己的應用程序域中,然后在完成程序集的搜索之后卸載應用程序域。


clip_image003我正在用一個基于模板的庫源代碼,該庫包含一些針對特定類型的模板函數特化。類模板,函數模板和模板函數特化都在頭文件中。我在我的.cpp文件中 #include 頭文件并編譯鏈接工程。但是為了在整個工程中使用該庫,我將頭文件包含在 stdafx.h 中,結果出現特化模板函數的符號多重定義錯誤。我要如何組織頭文件才能避免多重符號定義錯誤?我用 /FORCE:MULTIPLE,但我想用一個更好的解決方法。

Lee Kyung Jun


clip_image004
實際上,確實用更好的解決方法。稍后我會解釋,但首先讓我重溫一下模板函數特化是如何工作的。假設你有一個比較兩個基于 operator> operator== 對象的模板函數:

template <typename T>
int compare(T t1, T t2)
{
   return t1==t2 ? 0 : t1 > t2 ? 1 : -1;
}

  該模板根據地一個參數是否等于、大于、或小于第二個參數而分別返回零或+/-1。它是典型的用于集合排序時的排序函數。它假設類型 T 具備 operator== operator> 操作,并支持 intfloatdouble DWORD 類型。但它不能應用于比較自負串(char* 指針),因為這個函數比較的是串指針,而不是字符串本身:

LPCTSTR s1,s2;
...
int cmp = compare(s1,s2); // s1<s2? Oops!

為了能進行字符串比較,你需要一個使用 strcmp 或其 TCHAR 版本 _tcscmp 的模板特化:

// specialization for strings
template<>
int compare<LPCTSTR>(LPCTSTR s1, LPCTSTR s2)
{
    return _tcscmp(s1, s2);
}

  沒錯,這樣做完全正確,現在的問題是:將這個特化放在何處?顯然是要放在模板的頭文件中。但這樣會導致符號多重定義的錯誤,就像 Lee 遇到的那樣。原因很明顯,模板特化是一個函數,而非模板。它與下面的寫法是一樣的:

int compare(LPCTSTR s1, LPCTSTR s2)
{
    return _tcscmp(s1, s2);
}

  沒有理由不在頭文件中定義函數——但是一旦這樣做了,那么你便無法在多個文件中 #include 該頭文件。至少,肯定會有鏈接錯誤。怎么辦呢?
  如果你掌握了模板函數特化即函數,而非模板的概念,你就會認識到有三個選項,完全與普通函數一樣;特化為 inlineextern 或者 static。例如,像下面這樣:

template<>
inline int compare<LPCTSTR>(LPCTSTR s1, LPCTSTR s2)
{
    return _tcscmp(s1, s2);
}

  對于大多數模板庫而言,這是最容易和最常見的解決方案。因為編譯器直接擴展內聯函數,不產生外部符號,在多個模塊中 #include 它們沒有什么問題。鏈接器不會出錯,因為不存在多重定義的符號。對于像 compare 這樣的小函數來說,inline 怎么說都是你想要的(它更快)。
  但是,如果你的特化很長,或出于某種原因,你不想讓它成為 inline,那要如何做呢?此時可以做成 extern。語法與常規函數一樣:

// in .h header file
template<>
extern int compare<LPCTSTR>(LPCTSTR s1, LPCTSTR s2);

  當然,你得在某個地方實現 compare。部分細節如 Figure 7 所示。我在單獨的模塊 Templ.cpp 中實現了特化,它與主工程鏈接。Templ.h #include stdafx.h 中,而 stdafx.h 又被 #include Templ.cpp 和主模塊兩個文件中——生成工程沒有鏈接錯誤。去下載源代碼自己嘗試一下吧。
  如果你正在為其他開發人員寫模板庫,extern 方式會很不爽,因為你必須創建一個帶目標模塊的鏈接庫(lib),它包含有特化。如果你已經有了一個這樣的 .lib,也沒什么;如果沒有,你可能會想方設法避免引入這樣的庫。僅用頭文件實現模板是更好的方法(麻煩少)。最容易的方式是用 inline,此外,你還能將你的特化放在單獨的頭文件中,使之與其聲明分開并要其他開發人員只在一個模塊中 #include 特化。還有一個可選的方法是將所有東西放在一個文件中,并用預處理符號控制實例化:

#ifdef MYLIB_IMPLEMENT_FUNCS
template<>
int compare<LPCTSTR>(LPCTSTR s1, LPCTSTR s2)
{
    return _tcscmp(s1, s2);
}
#endif

  使用該方法,所有模塊都包含此頭文件,但在包含它之前,只有一個 #define MYLIB_IMPLEMENT_FUNCS。這個方法不支持預編譯頭,因為編譯器用 stdafx.h 中的任何 MYLIB_IMPLEMENT_FUNCS 值加載預編譯版本。
  避免符號多重定義錯誤的最后同時也是用得最少的一個方法是將特化做成 static

template<>
static int compare<LPCTSTR>(LPCTSTR s1, LPCTSTR s2)
{
    return _tcscmp(s1, s2);
}

  這樣鏈接器也不會出錯,因為靜態函數不向外界輸出其函數,并且它讓你將所有東西都保持在一個頭文件中,不用引入預處理符號。但它缺乏效率,因為每個模塊都有一個函數拷貝。如果函數小到沒什么——那為何不用內聯呢?
  所以簡言之:將特化做成 inline extern。通常都是用 inline。兩種方法都得編輯頭文件。如果使用的是第三方的庫沒有頭文件,那么你除了用鏈接選項 /FORCE:MULTIPLE 之外別無選擇。在你等著生成你的工程時,你可以告訴編寫庫文件的那個家伙——為什么要將函數模板特化定義成 inline 或者 extern。就說是我說的。

您的提問和評論可發送到 Paul 的信箱:cppqa@microsoft.com.
 

posted on 2008-10-13 11:25 肥仔 閱讀(1604) 評論(0)  編輯 收藏 引用 所屬分類: C++ 模板

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美在线高清| 欧美成人tv| 另类天堂视频在线观看| 国产午夜精品视频| 卡一卡二国产精品| 日韩一区二区久久| 久久精品中文字幕一区| 亚洲春色另类小说| 欧美日韩一区三区| 性欧美xxxx大乳国产app| 美女国产一区| 亚洲一区免费看| 精品盗摄一区二区三区| 欧美日韩免费观看一区| 欧美一区二区观看视频| 亚洲高清av| 香蕉乱码成人久久天堂爱免费 | 欧美激情亚洲| 亚洲一区不卡| 伊人成人开心激情综合网| 欧美精品日韩www.p站| 亚洲一区二区3| 欧美国产视频在线| 午夜国产精品视频| 最新中文字幕一区二区三区| 国产精品每日更新| 鲁鲁狠狠狠7777一区二区| 中日韩视频在线观看| 欧美mv日韩mv国产网站| 午夜精品久久久久久久久久久久久 | 久久久久www| 99国产精品国产精品久久| 久久躁日日躁aaaaxxxx| 宅男噜噜噜66一区二区66| 狠狠干狠狠久久| 欧美性猛交xxxx免费看久久久| 久久亚洲欧美国产精品乐播| 亚洲一区影音先锋| 亚洲精品一区二区网址 | 亚洲高清网站| 久久米奇亚洲| 欧美一级大片在线免费观看| a4yy欧美一区二区三区| 好吊色欧美一区二区三区视频| 欧美午夜不卡在线观看免费| 久久亚洲综合网| 久久精品亚洲一区| 亚洲欧美日本伦理| 这里只有精品视频在线| 亚洲激情第一区| 欧美国产日韩亚洲一区| 久久精品91久久久久久再现| 亚洲欧美中文字幕| 亚洲每日在线| 亚洲国产专区校园欧美| 狠狠色丁香久久综合频道| 国产精品一区二区三区成人| 国产精品v一区二区三区 | 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 91久久精品国产91久久| 欧美国产在线视频| 欧美激情亚洲| 亚洲国产精品免费| 亚洲第一区在线| 亚洲国产成人久久综合一区| 欧美+亚洲+精品+三区| 欧美福利电影网| 亚洲国产mv| 日韩视频免费| 亚洲桃花岛网站| 亚洲女爱视频在线| 亚洲国产女人aaa毛片在线| 禁断一区二区三区在线 | 日韩亚洲不卡在线| 99热免费精品| 亚洲一区二区三区欧美| 亚洲主播在线播放| 欧美一级二区| 久久精品夜色噜噜亚洲aⅴ| 久久影视精品| 欧美顶级艳妇交换群宴| 亚洲人成网站影音先锋播放| 亚洲裸体视频| 亚洲一区在线观看视频 | 夜夜嗨av一区二区三区| 一区二区欧美国产| 午夜天堂精品久久久久| 久久精品国产一区二区电影| 噜噜噜噜噜久久久久久91 | 夜夜嗨网站十八久久| 亚洲永久在线观看| 久久av免费一区| 美国十次了思思久久精品导航| 欧美激情亚洲| 国产精品美女久久久久久久| 国产午夜精品久久久| 亚洲国产成人精品久久久国产成人一区 | 久久婷婷久久| 亚洲国产一区在线| 亚洲午夜女主播在线直播| 欧美伊人久久大香线蕉综合69| 免费观看成人网| 国产精品福利av| 又紧又大又爽精品一区二区| 亚洲免费成人| 久久久久欧美精品| 亚洲欧洲精品天堂一级| 亚洲综合成人在线| 欧美aa国产视频| 国产欧美日韩激情| 亚洲美女一区| 久久这里有精品视频| 日韩午夜精品| 久久久噜噜噜久久中文字免| 欧美久久久久中文字幕| 国产一区二区三区精品久久久| 99精品福利视频| 久久亚洲欧美国产精品乐播| 亚洲精品中文字| 久久久久综合网| 国产伦精品一区二区三区照片91| 亚洲精品欧美日韩| 开心色5月久久精品| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 免费成人小视频| 亚洲在线视频一区| 欧美日本精品| 亚洲第一中文字幕在线观看| 亚洲欧美在线高清| 91久久综合| 免费久久99精品国产| 国内精品视频在线播放| 亚洲一区二区三区视频播放| 欧美激情区在线播放| 久久黄色影院| 国产欧美一区视频| 午夜精品久久| 99国产精品视频免费观看| 男男成人高潮片免费网站| 国产在线播放一区二区三区 | 欧美在线亚洲在线| 中国女人久久久| 欧美三区在线观看| 中日韩视频在线观看| 91久久线看在观草草青青| 久久亚洲精品一区| 在线成人激情| 农夫在线精品视频免费观看| 亚洲欧美伊人| 国产欧美一区二区精品性| 亚洲欧美资源在线| 亚洲一区二区精品在线观看| 欧美午夜大胆人体| 亚洲午夜羞羞片| 一本色道久久| 国产精品久久久久秋霞鲁丝| 亚洲一区二区在线播放| 日韩天堂av| 国产精品99免费看| 亚洲欧美日韩另类| 亚洲一级黄色av| 国产人久久人人人人爽| 欧美一区二区三区在线看| 亚洲欧美影音先锋| 黑人巨大精品欧美黑白配亚洲| 久久视频一区| 久久久夜精品| 亚洲茄子视频| av成人免费在线| 国产精品免费电影| 欧美在线国产精品| 欧美在现视频| 亚洲国产91| 日韩视频在线播放| 国产精品美女主播在线观看纯欲| 欧美一区三区三区高中清蜜桃| 欧美亚洲三区| 亚洲成色精品| 99亚洲精品| 国产欧美日韩精品一区| 久久人人看视频| 欧美高清在线精品一区| 亚洲天堂网在线观看| 午夜欧美理论片| 最新国产拍偷乱拍精品 | 欧美日韩国产精品成人| 亚洲欧美日韩在线不卡| 欧美综合激情网| 亚洲精品日韩在线| 亚洲午夜在线观看| 悠悠资源网久久精品| 亚洲精品国产精品国自产观看| 国产精品美女久久| 欧美成人日韩| 国产精品日韩精品| 欧美韩日一区二区| 国产精品久久久久久模特| 久久尤物电影视频在线观看| 欧美理论在线播放| 久久精品视频99|