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

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
<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用鏈接

留言簿(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>
            欧美日韩视频在线| 亚洲视频999| 国产精品无码永久免费888| 免费观看在线综合色| 亚洲调教视频在线观看| 99热在线精品观看| 国产欧美日韩激情| 国产美女诱惑一区二区| 国产热re99久久6国产精品| 国产久一道中文一区| 亚洲乱码国产乱码精品精天堂| 在线亚洲自拍| 欧美一级夜夜爽| 欧美大色视频| 亚洲春色另类小说| 久久一区二区三区国产精品 | 亚洲乱亚洲高清| 国产精品亚洲精品| 久久综合久久综合久久| 美女免费视频一区| 在线精品视频在线观看高清| 日韩亚洲欧美成人| 欧美与欧洲交xxxx免费观看 | 亚洲天堂视频在线观看| …久久精品99久久香蕉国产| 日韩视频精品在线观看| 亚洲桃花岛网站| 欧美成人国产va精品日本一级| 牛夜精品久久久久久久99黑人 | 在线免费观看日本一区| 亚洲二区在线视频| 亚洲视频在线观看| 欧美国产国产综合| 久久黄色网页| 国产揄拍国内精品对白 | 最新成人av网站| 亚洲免费影院| 亚洲国产精品传媒在线观看 | 亚洲欧美日韩精品| 欧美日本国产在线| 亚洲欧美一区二区在线观看| 久久不见久久见免费视频1| 久久嫩草精品久久久精品一| 欧美a级在线| 欧美成人午夜免费视在线看片| 国产欧美欧美| 欧美在线亚洲| 亚洲综合日韩在线| 国产在线国偷精品产拍免费yy| 欧美成人在线免费观看| 国产精品亚洲综合久久| 亚洲欧美精品| 久久国产乱子精品免费女| 在线观看欧美视频| 欧美福利视频网站| 久久久久在线| 日韩视频在线一区二区三区| 亚洲综合不卡| 在线观看日产精品| 亚洲精品在线二区| 欧美精品日日鲁夜夜添| 久久久999精品| 亚洲人成在线影院| 久久一区亚洲| 另类酷文…触手系列精品集v1小说| 蜜桃久久av一区| 香蕉乱码成人久久天堂爱免费| 欧美成人首页| 亚洲国产小视频| 欧美亚洲在线观看| 亚洲精品乱码久久久久久久久| 免费久久99精品国产| 欧美午夜在线| 久久精品国产77777蜜臀 | 久久青青草原一区二区| 国产精品成人观看视频国产奇米| 久久久精品网| 国产欧美在线观看| 久久亚洲国产精品一区二区| 国产精品久久久久77777| 亚洲午夜激情网站| 欧美视频不卡| 亚洲免费在线播放| 亚洲五月婷婷| 国产欧美一区二区三区另类精品| 一二美女精品欧洲| 一区二区三区自拍| 国产一区二区三区无遮挡| 亚洲社区在线观看| 一区二区三区国产| 免费短视频成人日韩| 午夜视频一区在线观看| 欧美性事在线| 噜噜噜噜噜久久久久久91| 亚洲国产精品成人| 国产婷婷成人久久av免费高清 | 亚洲国产高潮在线观看| 亚洲午夜国产成人av电影男同| 午夜久久美女| 欧美国产亚洲精品久久久8v| 久久国内精品视频| 日韩一区二区精品视频| 欧美网站大全在线观看| 久久久91精品国产一区二区精品| 亚洲国产视频一区二区| 亚洲欧美日韩一区二区三区在线观看 | 亚洲精品资源| 亚洲影院免费| 久久久精品tv| 亚洲精品护士| 亚洲欧美中文另类| 亚洲人体影院| 国产精品一区视频| 欧美日韩a区| 久久久午夜电影| 久久婷婷国产综合国色天香| 欧美激情精品久久久久久黑人| 久久婷婷色综合| 亚洲综合首页| 一区二区国产日产| 在线免费观看日本一区| 欧美私人啪啪vps| 国产精品免费网站| 欧美日本国产精品| 国产精品扒开腿爽爽爽视频| 欧美成人r级一区二区三区| 亚洲欧美一区二区精品久久久| 亚洲小视频在线观看| 久久国产精品久久国产精品| 国产精品永久入口久久久| 免费观看成人www动漫视频| 久久米奇亚洲| 欧美日韩亚洲一区三区 | 欧美国产一区二区在线观看| 欧美亚洲视频在线看网址| 欧美一区二区在线免费观看| 久热综合在线亚洲精品| 欧美日韩成人| 亚洲国产欧美国产综合一区| 亚洲国产片色| 一区三区视频| 制服丝袜激情欧洲亚洲| 免费观看成人www动漫视频| 亚洲韩国青草视频| 久久国产精品72免费观看| 欧美日本不卡高清| 国产精品久99| 一区二区三区回区在观看免费视频| 久久久久国产一区二区三区| 亚洲国产一区视频| 久久久久久久成人| 欧美日韩在线不卡一区| 亚洲欧洲在线播放| 亚洲中字黄色| 日韩一级免费观看| 久久久久久久精| 黑人极品videos精品欧美裸| 亚洲区第一页| 老司机凹凸av亚洲导航| 久久久久久尹人网香蕉| 国产精品一区=区| 亚洲欧美一区在线| 亚洲一区bb| 亚洲国产一二三| 欧美不卡福利| 国产一区二区丝袜高跟鞋图片| 欧美专区在线播放| 久久综合亚州| 一区二区电影免费在线观看| 亚洲第一区在线| 99热这里只有精品8| 亚洲电影免费观看高清| 亚洲一本大道在线| 国产午夜精品全部视频在线播放| 亚洲一区二区视频在线| 久久久久久亚洲精品不卡4k岛国| 国内成人精品一区| 亚洲七七久久综合桃花剧情介绍| 久久免费视频在线观看| **性色生活片久久毛片| 久久精品亚洲国产奇米99| 亚洲欧美日韩综合aⅴ视频| 黑丝一区二区| 日韩视频精品| 欧美午夜片在线观看| 欧美一级播放| 久久精品亚洲| 亚洲精品免费在线| 欧美一区二区三区精品电影| 日韩视频在线观看国产| 一区二区国产精品| 国产欧美不卡| 亚洲一区二区三区视频| 国产视频一区免费看| 亚洲精品婷婷| 亚洲视频成人| 欧美日韩在线一区二区三区| 久久久久久久精| 国产欧美精品久久| 午夜一级在线看亚洲|