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

posts - 297,  comments - 15,  trackbacks - 0
出處 http://www.shnenglu.com/cexer/archive/2008/07/06/55484.html

  VC當中有一個鮮為人知的關鍵字,除了微軟自己的代碼,我從未在任何地方看到有人用過它。雖然它的功能很強大,不過除非設計上的問題或是一些無法排除的困難,否則幾乎從不會需要用到它的功能。但是有時候,它確實能作為一個最簡單的解決方案而讓某些設計過程事半功倍。

  借用 CCTV10《走近科學》的語氣:那么這個神秘的關鍵關鍵字到底是什么呢?它又實現了什么神奇的功能呢?帶著這一連串的疑問,讓我們先來看一個具體的例子。

  我在自己曾經寫的一個GUI框架當中,為了實現消息與處理函數自動映射的,就需要求助于這種功能。比如說有一個窗口類,它包含若干消息處理函數和一個消息與處理函數的映射 map:(請無視當中的 show() 和 create() 函數,與主題無關)

    class Window
{
typedef UINT _Message;
typedef LRESULT (Window::*_Handler)(_Message);

map<_Message,_Handler> m_handlerMap;

public:
bool show();
bool create();

public:
LRESULT onEvent( WindowEvent<WM_CREATE> );
LRESULT onEvent( WindowEvent<WM_DESTROY> );
};

  
  我需要利用模板元編程 從 0 到 WM_USER  進行循環檢測,檢測 Window 類是否存在該消息對應的處理函數。如果消息對應的處理函數存在,那么就將消息與函數的映射放進 m_handlerMap 當中。比如說消息 WM_CREATE,我檢測類 Window是否存在 LRESULT onEvent( WindowEvent<WM_CREATE> ) 成員函數,在上例代碼中是存在的,于是我將這樣一個映射放進m_handlerMap:(真正實現的時候,還要考慮函數的類型。不同類型的函數,是不能直 接裝進 map 當中的。不過在這里請無視例子當中涉及的所有類型轉換,與主題無關)

    pair<WM_CREATE,&Window::onEvent>


  這樣就達到了消息自動映射的目的。而不用像MFC一樣手寫宏去映射。(最后通過努力的確達到了我的目的,我的GUI框架能夠進行自動消 息映射了,然而可以預見,由于幾千個(0-WM_USER)循環,編譯期的速度受到極大影響。所以最終我還是拋棄了這種自動映射實現,而采用了更高效神奇 的方法,這是后話也與本主題無關就先不提)。

  要實現以上的自動映射功能就引出了這樣一個難題:如何編譯期檢測類的某特定名字的成員是否存在。

  功能不負有心人,經過爬山涉水翻山越嶺,我終于在 MSDN 一個偏遠角落里找著了傳說當中那個神秘的關鍵字:__if_exists(其實還有一個 __if_not_exists)。MSDN 當中這樣說明:__if_exists (__if_not_exists)允許你針對某符號的存在與否條件性地執行語句。使用語法:(注意檢測的是“存在性”,而不是值)

    __if_exists ( /*你要檢測存在性的函數或變量的名字*/ ) { 
 //做些有用的事
}


  MSDN當中的示例代碼如下:
    // the__if_exists_statement.cpp
// compile with: /EHsc
#include <iostream>

template<typename T>
class X : public T {
public:
void Dump() {
std::cout << "In X<T>::Dump()" << std::endl;

__if_exists(T::Dump) {
T::Dump();
}

__if_not_exists(T::Dump) {
std::cout << "T::Dump does not exist" << std::endl;
}
}
};

class A {
public:
void Dump() {
std::cout << "In A::Dump()" << std::endl;
}
};

class B {};

bool g_bFlag = true;

class C {
public:
void f(int);
void f(double);
};

int main() {
X<A> x1;
X<B> x2;

x1.Dump();
x2.Dump();

__if_exists(::g_bFlag) {
std::cout << "g_bFlag = " << g_bFlag << std::endl;
}

__if_exists(C::f) {
std::cout << "C::f exists" << std::endl;
}

return 0;
}


  以上代碼的輸出如下:(未測試,此輸出為MSDN的說明文檔當中的)

    In X<T>::Dump()
In A::Dump()
In X<T>::Dump()
T::Dump does not exist
g_bFlag = 1
C::f exists


  大概很少人見過這個關鍵字吧。雖然它們的功能與我的需求是如此的接近,但是面對如此強憾的關鍵字,我還是只能搖頭嘆息。我傷心地在文檔 里看到說明,__if_exists(__if_not_exists)關鍵字用于函數的時候,只能根據函數名字進行檢測,而會忽略對參數列表的檢測,因 此沒有對重載函數的分辨能力,而正是我需要的。比如類 Window 有一個函數:

    LRESULT Window::onEvent( WindowEvent<WM_DESTROY> )
{
//做些有用的事
}


  我用以下代碼來檢測 WM_CREATE 消息是否存在處理函數:

    __if_exists(Window::onEvent)
  {
      //添加消息映射
   }


  即使 Window 類當中不存在 LRESULT onEvent ( WindowEvent<WM_CREATE> ),以上測試也能通過。這是因為 __if_exists 關鍵字是不管函數重載的,如果存在一個 onEvent ,那么所有的檢測都能通過。這不是我想要的。我需要比 __if_exists 更強憾的檢測功能,強憾到能夠針對不同參數列表的同名函數(重載函數)做出正確的存在性測試。

  于是我繼續翻山越嶺地尋找,從 CSDN 到 MSDN,從 SourceForge 到 CodeProject。要相信那句老話:“有心人天不負”。最后我在 CodeProject 上面看到一篇讓我醍醐灌頂的文章:

  Interface Detection by Alexandre Courpron

  這篇文章從原理到實現,很詳細地說明地一種編譯期檢測技術,先說明一下,由于VC7.1數千個bug當中的一個,以下技術不能在VC++7.1或更低版本上使用。具體的實現在那篇文章當中說得很詳盡了,還是在這兒贅述一下。

  Alexandre Courpron的實現方式基于C++的這樣一個規則:Substitution Failure Is Not An Error (簡稱SFINAE)。它的含義我也理解得比較含糊,不過它作用于重載函數的時候,可以這樣理解:對于一個函數調用,在匹配函數的過程當中,如果最終能夠 有一個函數匹配成功,那么對其余函數的匹配如果失敗,編譯器也不會視為錯誤。聽起來有些麻煩,看Alexandre Courpron給出的例子:

    struct Test 
{
typedef int Type;
};

template < typename T >
void f(typename T::Type) {} // definition #1

template<typename T>
void f(T){} // definition #2

f<Test>(10); //call #1

f<int>(10); //call #2

  
  對于 call#1 編譯器直接匹配 definition#1 成功。對于 call#2,編譯器先用 definition#1 匹配 如下:

    void f( typename int::Type ) {}


  這顯然是不正確的。不過編譯器并沒有編譯失敗報告錯誤,因為下面的 definition#2 匹配成功,根據 SFINAE的 規則,編譯器有權保持沉默 。

  雖然是個小小的規則,在平時幾乎不會注意它。然而在這兒,我們卻可以利用它實現編譯期檢測的強大功能了,一個最簡單的示例:

    #include <iostream>
using namespace std;
//
struct TestClass
{
void testFun();
};

struct Exists { char x;};
struct NotExists { char x[2]; };

template <void (TestClass::*)()>
struct Param ;

template <class T>
Exists isExists( Param<&T::testFun>* );

template <class T>
NotExists isExists( ... );
//
int main()
{
cout<<sizeof(isExists<TestClass>(0))<<endl;
}


  上面的代碼會輸出 1。說明一下檢測的過程:

  1. 編譯器遇到 isExists<TestClass>(0) 這一句,會去匹配 isExists 的兩個重載函數。不定長的參數優先級更低,因此先匹配第一個函數。
  2. 第一個函數參數類型為 Param<&T::testFun>*,在這里是 Param<&TestClass::testFun>,編譯器在匹配這個參數類型的時候會嘗試實例化模板類 Param。
  3. 編 譯器嘗試用 &TestClass::testFun 去實例化 Param,因為 TestClass 確實存在一個 void (TestClass::*)() 類型,且名為 testFun 的成員函數。所以 Param 的實例化成功,因此參數匹配成功。
  4. 匹配第一個函數成功。編譯器決定 isExists<TestClass>(0) 這一句調用就是調用的第一個函數。
  5. 因為第一個函數返回的類型為 Exists,用 sizeof 取大小就是 1。

  如果是我們把 TestClass 的定義修改為:(僅把函數的參數類型改為 int )

    struct TestClass
{
void testFun(int);
};


  這一次代碼會輸出 2。因為在第3步的時候,由于 TestClass 沒有類型為 void (TestClass::*)(),且名為 testFun 的函數,所以實例化 Param 會失敗,因此匹配第一個函數失敗。然后編譯器去匹配第二個函數。因為其參數類型是任意的,自然會匹配成功。結果會輸出 2。

  當然這只是個最簡單的示例,通過模板包裝類。可以實現更靈活更強大的功能。比如回到那個自動消息映射的例子,用以下代碼就能夠實現了:

//c++std
#include <iostream>
using namespace std;




//windows
#include <windows.h>



//detector
template<typename TWindow,UINT t_msg>
struct MessageHandlerDetector
{
typedef WindowEvent<t_msg> _Event;

struct Exists {char x;};
struct NotExists {char x[2];};

template<LRESULT (TWindow::*)(_Event)>
struct Param;

template<typename T>
static Exists detect( Param<&T::onEvent>* );

template<typename T>
static NotExists detect( ... );

public:
enum{isExists=sizeof(detect<TWindow>(0))==sizeof(Exists)};
};

//test classes
struct Window
{
LRESULT onEvent( WindowEvent<WM_CREATE> );
};

struct Button
{
LRESULT onEvent( WindowEvent<WM_DESTROY> );
};

//main
int main()
{
cout<<MessageHandlerDetector<Window,WM_CREATE>::isExists<<endl;
cout<<MessageHandlerDetector<Window,WM_DESTROY>::isExists<<endl;
cout<<MessageHandlerDetector<Button,WM_CREATE>::isExists<<endl;
cout<<MessageHandlerDetector<Button,WM_DESTROY>::isExists<<endl;

return 0;
}




  以上代碼會輸出:

    1
0
0
1


  以上的示例代碼再加上模板元編程,可以很輕易地實現消息的自動映射,具體實現這個已不在本貼的討論范圍并且這種自動映射的實現,太過復雜,在編譯期沒有效率,且不夠靈活。不過在消息映射機制上來說,已稱得上是一種革命性的嘗試。

  在說完了這所有一切之后,再告訴你一個我最近才知道的秘密(不準笑我孤陋寡聞):其實 boost 庫當中已有相關功能的 MPL  工具存在,叫做 has_xxx。

  源文件:<boost\mpl\has_xxx.hpp>

  文檔:http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html

posted on 2008-07-19 13:50 chatler 閱讀(488) 評論(0)  編輯 收藏 引用 所屬分類: VC_MFC
<2009年2月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
1234567

常用鏈接

留言簿(10)

隨筆分類(307)

隨筆檔案(297)

algorithm

Books_Free_Online

C++

database

Linux

Linux shell

linux socket

misce

  • cloudward
  • 感覺這個博客還是不錯,雖然做的東西和我不大相關,覺得看看還是有好處的

network

OSS

  • Google Android
  • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
  • os161 file list

overall

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久性天堂网| 欧美怡红院视频| 娇妻被交换粗又大又硬视频欧美| 欧美日韩精品免费观看视频完整 | 欧美日韩123| 久久精品国产清自在天天线| 中文亚洲欧美| 亚洲精品乱码久久久久| 久久精品中文| 午夜精品久久久久久久| 一本一本久久| 91久久精品国产91久久性色| 国产综合香蕉五月婷在线| 欧美视频在线看| 欧美精品系列| 欧美激情视频给我| 蜜桃久久精品乱码一区二区| 久久久www成人免费精品| 亚洲自拍偷拍麻豆| 国产精品99久久久久久久久久久久| 亚洲国产成人av在线| 免费看av成人| 欧美 日韩 国产一区二区在线视频| 欧美中文字幕视频在线观看| 性欧美暴力猛交另类hd| 亚洲女ⅴideoshd黑人| 亚洲手机在线| 亚洲一区二区在| 亚洲无限av看| 亚洲在线成人精品| 亚洲女同同性videoxma| 亚洲一区自拍| 欧美亚洲一区| 久久久久久网站| 久久在线免费观看视频| 久久综合久色欧美综合狠狠 | 久久久久国产精品一区| 久久精品视频在线播放| 久久精品视频va| 老司机午夜精品视频| 久久在线视频在线| 欧美电影在线观看| 欧美日韩另类综合| 国产精品成人va在线观看| 国产精品午夜国产小视频| 国产精品自拍在线| 黑丝一区二区| 亚洲国产另类精品专区| 99re6这里只有精品| 亚洲视频免费观看| 欧美中文在线免费| 美女精品自拍一二三四| 亚洲激情影视| 亚洲一区二区三区色| 午夜精品亚洲| 久久久综合视频| 欧美精品一区三区| 国产精品嫩草久久久久| 韩国v欧美v日本v亚洲v| 亚洲福利视频二区| 亚洲视频每日更新| 久久精品一区二区国产| 亚洲第一免费播放区| 中文国产成人精品| 久久久精品国产一区二区三区 | 国产美女精品人人做人人爽| 激情久久婷婷| 一本色道久久加勒比88综合| 性感少妇一区| 亚洲国产老妈| 亚洲一区二区三区激情| 久久精品国产清自在天天线| 欧美日本国产在线| 国产偷国产偷亚洲高清97cao| 亚洲高清视频一区| 亚洲欧美日韩一区二区三区在线| 另类av一区二区| 亚洲美女视频网| 久久久久久久网站| 国产精品igao视频网网址不卡日韩| 国产专区欧美精品| 亚洲午夜视频在线| 欧美 日韩 国产在线| 亚洲影视在线播放| 欧美国产亚洲精品久久久8v| 国产日产欧产精品推荐色 | 亚洲自拍偷拍麻豆| 欧美高清在线视频| 国产综合在线看| 亚洲一区二区三区高清| 欧美成熟视频| 久久av一区二区三区| 国产精品爱久久久久久久| 亚洲国产精品电影| 久久久99国产精品免费| 中文无字幕一区二区三区| 欧美大胆人体视频| 狠狠干成人综合网| 欧美一区二区在线播放| 亚洲精品一线二线三线无人区| 久久精品男女| 国产欧美一区二区三区沐欲| 亚洲特级毛片| 亚洲激情视频在线观看| 久久亚洲风情| 激情综合激情| 久久精品国产99国产精品| 一区二区三区高清| 欧美日韩精品国产| 日韩网站在线| 亚洲国产aⅴ天堂久久| 久久视频在线免费观看| 韩国成人精品a∨在线观看| 欧美一级久久久| 亚洲一区二区三区国产| 欧美午夜宅男影院在线观看| 一区二区欧美日韩| 亚洲国产欧美另类丝袜| 欧美成黄导航| 亚洲人人精品| 亚洲国产精品一区在线观看不卡 | 久久综合九色欧美综合狠狠| 午夜精品福利一区二区蜜股av| 欧美午夜宅男影院在线观看| 亚洲性感激情| 亚洲午夜黄色| 国产精品色网| 欧美在线啊v| 午夜亚洲福利| 韩国欧美国产1区| 蜜月aⅴ免费一区二区三区| 久久久久免费视频| 亚洲二区免费| 最近中文字幕日韩精品 | 亚洲欧洲另类| 欧美精品一区二区三区蜜桃 | 国产精品99久久久久久久vr| 国产精品成人一区二区三区吃奶| 亚洲欧美日韩一区二区| 午夜久久电影网| 伊人久久综合97精品| 亚洲成在人线av| 欧美日韩国产片| 午夜亚洲福利| 久久久高清一区二区三区| 亚洲国产精品黑人久久久| 亚洲国产精品尤物yw在线观看| 欧美日本二区| 亚洲欧美视频在线| 久久国产精品久久久久久久久久| 尤物yw午夜国产精品视频| 欧美黄色影院| 国产精品成人播放| 久久久久国产一区二区三区四区| 久久久久一区二区| 99国产精品自拍| 亚洲一区二区三区精品在线| 好看的日韩视频| 91久久夜色精品国产九色| 国产精品久久二区| 麻豆精品视频在线| 欧美日韩免费在线| 久久精品成人一区二区三区蜜臀| 久久久99久久精品女同性| 亚洲美女视频在线免费观看| 亚洲视频一区| 在线日韩精品视频| 国产精品99久久久久久人| 精品51国产黑色丝袜高跟鞋| 亚洲精品乱码| 黄色一区二区三区四区| 亚洲毛片在线看| 黄色小说综合网站| 日韩午夜精品视频| 伊人久久亚洲热| 艳女tv在线观看国产一区| 韩国成人精品a∨在线观看| 亚洲精品乱码久久久久久黑人| 国产视频一区欧美| 日韩视频亚洲视频| 亚洲高清久久| 亚洲免费影视| 亚洲精品在线免费观看视频| 午夜精品久久久久久久蜜桃app| 最近看过的日韩成人| 亚洲砖区区免费| aa亚洲婷婷| 久久综合久久久久88| 先锋影音久久久| 欧美日韩高清免费| 欧美不卡一区| 国产一区二区三区在线免费观看 | 亚洲午夜伦理| 免费观看日韩| 久久久国产午夜精品| 欧美日韩美女一区二区| 欧美激情视频一区二区三区在线播放 | 一本色道久久综合亚洲91| 久久久久久伊人| 久久精品日韩欧美|