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

posts - 297,  comments - 15,  trackbacks - 0
出處 http://m.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 閱讀(482) 評論(0)  編輯 收藏 引用 所屬分類: VC_MFC
<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用鏈接

留言簿(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>
            美女在线一区二区| 欧美一区二区在线看| 亚洲欧美大片| 欧美大片免费观看在线观看网站推荐| 小黄鸭精品aⅴ导航网站入口| 亚洲在线观看视频网站| 欧美伦理影院| 亚洲精品在线免费观看视频| 亚洲一区影院| 老司机亚洲精品| 最新亚洲视频| 欧美中文字幕视频| 欧美一区二区三区播放老司机| 国产精品素人视频| 老司机67194精品线观看| 国产一区二区看久久| 欧美在线不卡| 欧美日本高清| 一区二区精品| 国产精品久久久久久户外露出 | 欧美精品在线观看91| 亚洲精品国产精品国产自| 欧美日韩视频在线一区二区 | 亚洲国产精品成人精品| 亚洲国产女人aaa毛片在线| 欧美日韩在线免费观看| 欧美精品久久99| 欧美激情按摩| 久久久久久久欧美精品| 亚洲第一网站免费视频| 一本色道久久88精品综合| 久久精品人人做人人综合| 久久久久久高潮国产精品视| 男同欧美伦乱| 欧美精品久久久久久久免费观看| 国产一区二区精品在线观看| 欧美激情中文字幕在线| 久久国内精品自在自线400部| 午夜电影亚洲| 亚洲美女黄网| 国产精品毛片大码女人| 久久久亚洲欧洲日产国码αv | 亚洲欧洲一区二区三区久久| 麻豆freexxxx性91精品| 在线精品国产欧美| 国产在线不卡| 亚洲精品免费一区二区三区| 最新成人av在线| 欧美激情亚洲激情| 国产精品久在线观看| 欧美日韩另类综合| 欧美精品国产精品日韩精品| 亚久久调教视频| 亚洲免费观看高清在线观看 | 亚洲精品欧美精品| 亚洲国产精选| 国产精品久久久久久久一区探花 | 在线一区二区日韩| 亚洲日本中文字幕| 在线视频欧美日韩精品| 激情久久一区| 亚洲香蕉在线观看| 永久免费精品影视网站| 久久av一区二区| 国产精品视频999| 国产丝袜一区二区| 亚洲精品一区在线| 亚洲久色影视| 欧美在线日韩| 欧美激情第9页| 久久精品国产亚洲aⅴ| 久久免费精品视频| 最新亚洲激情| 久久aⅴ国产欧美74aaa| 9人人澡人人爽人人精品| 亚洲精品久久久久久一区二区| 午夜精品短视频| 这里只有精品视频在线| 国产视频一区二区三区在线观看| 欧美一级欧美一级在线播放| 国产精品久久久对白| 亚洲国产成人一区| 欧美精品999| 99视频+国产日韩欧美| 久久久久久久999| 欧美一级大片在线免费观看| 精品成人一区二区| 亚洲国产欧美久久| 国产一区二区三区直播精品电影 | 欧美一区二区三区日韩视频| 亚洲国产精品999| 国内视频一区| 国产区日韩欧美| 国产日韩欧美一区二区| 亚洲免费一在线| 久久一区二区三区四区五区| 国产精品mv在线观看| 亚洲精品日产精品乱码不卡| 国产麻豆午夜三级精品| 亚洲女人天堂成人av在线| 在线播放亚洲| 久久se精品一区二区| 欧美国产精品久久| 久久er精品视频| 亚洲电影欧美电影有声小说| 欧美福利影院| 欧美视频在线一区二区三区| 亚洲一区免费| 免费观看一级特黄欧美大片| 美女视频网站黄色亚洲| 亚洲国产美女| 亚洲黄色小视频| 黄色日韩网站| 国产精品永久| 伊人婷婷欧美激情| 一本大道久久a久久综合婷婷| 亚洲大片免费看| 亚洲福利视频一区二区| 国产精品久久久久av免费| 欧美特黄一区| 亚洲激情在线播放| 99re这里只有精品6| 日韩亚洲在线| 日韩午夜av电影| 一本久道久久综合中文字幕| 欧美一区二区免费观在线| 亚洲高清中文字幕| 国精品一区二区| 国产精品永久免费| 亚洲激情在线观看视频免费| 一区二区三区不卡视频在线观看| 在线视频你懂得一区二区三区| 亚洲视频免费看| 亚洲图色在线| 亚洲欧美一区二区三区在线| 欧美国产日韩二区| 亚洲伊人一本大道中文字幕| 久久久综合网站| 亚洲国产欧美国产综合一区| 欧美一区二区三区视频| 亚洲欧美日韩精品久久| 亚洲一级在线观看| 欧美日韩午夜剧场| 宅男噜噜噜66一区二区| 亚洲综合欧美日韩| 国产精品手机在线| 亚洲制服少妇| 久久国产精品久久国产精品| 国内精品久久久久影院 日本资源| 欧美在线免费| 欧美成人精品一区| 亚洲精品中文字幕在线| 欧美日韩在线视频观看| 亚洲一区二区三区涩| 久久成人国产精品| 1769国产精品| 欧美久久久久久久久久| 亚洲午夜电影| 鲁大师影院一区二区三区| 亚洲精品欧美精品| 欧美亚男人的天堂| 欧美一级片一区| 亚洲电影下载| 亚洲综合第一| 在线免费高清一区二区三区| 欧美激情va永久在线播放| 99精品黄色片免费大全| 欧美一级视频精品观看| 雨宫琴音一区二区在线| 欧美日韩精品伦理作品在线免费观看 | 久久躁狠狠躁夜夜爽| 一区二区三区在线免费播放| 久久久亚洲一区| 亚洲欧美在线免费观看| 国产综合av| 欧美精品一二三| 西瓜成人精品人成网站| 欧美成年人在线观看| 亚洲一区二区三| 在线精品国精品国产尤物884a| 欧美日韩精品久久久| 久久精品欧洲| 亚洲视频导航| 欧美电影打屁股sp| 欧美一区二区精品久久911| 亚洲激情在线激情| 国产一区二区成人| 欧美视频中文一区二区三区在线观看 | 久久久美女艺术照精彩视频福利播放| 久久久噜噜噜久久| 亚洲人成亚洲人成在线观看图片| 国产精品视频久久| 欧美精品日韩| 老鸭窝毛片一区二区三区| 亚洲欧美日韩另类| 亚洲精品系列| 91久久精品国产91久久性色tv| 久久嫩草精品久久久精品| 性欧美长视频| 亚洲欧美中文日韩在线|