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

cexer

cexer
posts - 12, comments - 334, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

轉(zhuǎn)帖請注明出處 http://m.shnenglu.com/cexer/archive/2008/07/06/55484.html

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

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

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

    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  進(jìn)行循環(huán)檢測,檢測 Window 類是否存在該消息對應(yīng)的處理函數(shù)。如果消息對應(yīng)的處理函數(shù)存在,那么就將消息與函數(shù)的映射放進(jìn) m_handlerMap 當(dāng)中。比如說消息 WM_CREATE,我檢測類 Window是否存在 LRESULT onEvent( WindowEvent<WM_CREATE> ) 成員函數(shù),在上例代碼中是存在的,于是我將這樣一個(gè)映射放進(jìn)m_handlerMap:(真正實(shí)現(xiàn)的時(shí)候,還要考慮函數(shù)的類型。不同類型的函數(shù),是不能直接裝進(jìn) map 當(dāng)中的。不過在這里請無視例子當(dāng)中涉及的所有類型轉(zhuǎn)換,與主題無關(guān))

    pair<WM_CREATE,&Window::onEvent>


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

  要實(shí)現(xiàn)以上的自動(dòng)映射功能就引出了這樣一個(gè)難題:如何編譯期檢測類的某特定名字的成員是否存在。

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

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


  MSDN當(dāng)中的示例代碼如下:
    // 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的說明文檔當(dāng)中的)

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


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

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


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

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


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

  于是我繼續(xù)翻山越嶺地尋找,從 CSDN 到 MSDN,從 SourceForge 到 CodeProject。要相信那句老話:“有心人天不負(fù)”。最后我在 CodeProject 上面看到一篇讓我醍醐灌頂?shù)奈恼拢?/p>

  Interface Detection by Alexandre Courpron

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

  Alexandre Courpron的實(shí)現(xiàn)方式基于C++的這樣一個(gè)規(guī)則:Substitution Failure Is Not An Error(簡稱SFINAE)。它的含義我也理解得比較含糊,不過它作用于重載函數(shù)的時(shí)候,可以這樣理解:對于一個(gè)函數(shù)調(diào)用,在匹配函數(shù)的過程當(dāng)中,如果最終能夠有一個(gè)函數(shù)匹配成功,那么對其余函數(shù)的匹配如果失敗,編譯器也不會(huì)視為錯(cuò)誤。聽起來有些麻煩,看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 ) {}


  這顯然是不正確的。不過編譯器并沒有編譯失敗報(bào)告錯(cuò)誤,因?yàn)橄旅娴?definition#2 匹配成功,根據(jù) SFINAE的 規(guī)則,編譯器有權(quán)保持沉默 。

  雖然是個(gè)小小的規(guī)則,在平時(shí)幾乎不會(huì)注意它。然而在這兒,我們卻可以利用它實(shí)現(xiàn)編譯期檢測的強(qiáng)大功能了,一個(gè)最簡單的示例:

    #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;
}


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

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

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

    struct TestClass
{
void testFun(int);
};


  這一次代碼會(huì)輸出 2。因?yàn)樵诘冢巢降臅r(shí)候,由于 TestClass 沒有類型為 void (TestClass::*)(),且名為 testFun 的函數(shù),所以實(shí)例化 Param 會(huì)失敗,因此匹配第一個(gè)函數(shù)失敗。然后編譯器去匹配第二個(gè)函數(shù)。因?yàn)槠鋮?shù)類型是任意的,自然會(huì)匹配成功。結(jié)果會(huì)輸出 2。

  當(dāng)然這只是個(gè)最簡單的示例,通過模板包裝類。可以實(shí)現(xiàn)更靈活更強(qiáng)大的功能。比如回到那個(gè)自動(dòng)消息映射的例子,用以下代碼就能夠?qū)崿F(xiàn)了:

//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;
}



  以上代碼會(huì)輸出:

    1
0
0
1


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

  在說完了這所有一切之后,再告訴你一個(gè)我最近才知道的秘密(不準(zhǔn)笑我孤陋寡聞):其實(shí) boost 庫當(dāng)中已有相關(guān)功能的 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

Feedback

# re: C++編譯期函數(shù)/變量檢測技術(shù),超越VC的某某關(guān)鍵字  回復(fù)  更多評論   

2008-07-06 23:54 by Bill Gates
不就是traits嗎

# re: C++編譯期函數(shù)/變量檢測技術(shù),超越VC的某某關(guān)鍵字  回復(fù)  更多評論   

2008-07-06 23:56 by cexer
不是。并不是涉及模板就能用traits來說事的。

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2008-07-08 18:29 by 周星星
好方法呀,俺也一直在尋找 __if_exists 的替代方法(用標(biāo)準(zhǔn)C++語法)

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2008-07-08 19:50 by cexer
你可以看看,boost有更好的實(shí)現(xiàn)。

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2008-07-10 23:13 by 夢在天涯
沒用過,有難度,長見識(shí)!

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2008-08-19 12:47 by 螞蟻終結(jié)者
不錯(cuò),有點(diǎn)意思。

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2009-09-24 11:20 by pipilu
問一下怎么編譯器比較兩個(gè)常數(shù)來設(shè)置編譯呢

#define AAA 12

// 如果 AAA > 12 則編譯下面內(nèi)容
bool bUse = 134;

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2012-06-01 01:09 by 春秋十二月
不錯(cuò) 受益了

# re: C++編譯期函數(shù)/變量檢測技術(shù),仿真VC關(guān)鍵字__if_exists  回復(fù)  更多評論   

2013-05-30 14:01 by zirandeai
我覺得這只是語法糖,增加了復(fù)雜度,卻并未讓人看到實(shí)質(zhì)性的好處
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久久久久9| 欧美色图五月天| 久久久久久久久久久久久女国产乱 | 欧美精品xxxxbbbb| 欧美在线免费播放| 久久福利一区| 欧美一区二区观看视频| 亚洲一区二区三区精品视频| 亚洲精品美女在线| 亚洲乱码久久| 夜夜嗨av一区二区三区免费区| 亚洲人成人一区二区在线观看 | 国产欧美日韩91| 国产欧美一区二区色老头| 国产精品影片在线观看| 国产亚洲精品v| 国内久久婷婷综合| 艳妇臀荡乳欲伦亚洲一区| 亚洲欧美一区二区激情| 久久综合伊人77777尤物| 亚洲人成网在线播放| 亚洲综合国产激情另类一区| 亚洲欧美网站| 欧美精品在线一区二区| 国产亚洲欧美另类中文| 这里只有精品在线播放| 久久激情视频| 亚洲一区中文| 欧美日韩和欧美的一区二区| 国产色综合网| 羞羞色国产精品| 日韩一级片网址| 欧美成人官网二区| 亚洲黄色影片| 亚洲三级观看| 久久在精品线影院精品国产| 99精品视频一区二区三区| 久久综合精品一区| 激情一区二区三区| 久久精品久久99精品久久| 99re视频这里只有精品| 欧美成人资源网| 亚洲区第一页| 91久久精品国产91性色| 老鸭窝毛片一区二区三区| 韩国美女久久| 欧美高清视频| 欧美性感一类影片在线播放 | 国产日韩精品一区二区| 中文一区字幕| 亚洲午夜av电影| 国产一级一区二区| 免费观看成人www动漫视频| 美女视频网站黄色亚洲| 亚洲一区二区三区中文字幕| 中日韩在线视频| 国产一区二区中文字幕免费看| 久久亚洲欧美国产精品乐播| 久久岛国电影| 亚洲一区二区三区四区在线观看| 亚洲网站视频福利| 亚洲电影免费在线观看| 99伊人成综合| 亚洲乱码国产乱码精品精天堂 | 亚洲人午夜精品| 亚洲自啪免费| 亚洲国产综合在线看不卡| 亚洲午夜性刺激影院| 一色屋精品视频免费看| 亚洲一区三区电影在线观看| 亚洲肉体裸体xxxx137| 久久久久国产精品人| 一区二区三区蜜桃网| 男人的天堂亚洲| 美女视频网站黄色亚洲| 国产一区二区三区四区五区美女| 亚洲人成人一区二区三区| 亚洲理伦在线| 欧美日韩成人一区二区| 亚洲精品一线二线三线无人区| 国产在线视频欧美| 欧美自拍偷拍午夜视频| 久久人人看视频| 1024国产精品| 欧美激情麻豆| 亚洲欧美国产毛片在线| 欧美一区深夜视频| 国内精品福利| 欧美大片在线观看| 亚洲一区二区在线看| 欧美一区二区在线播放| 国内精品国产成人| 亚洲高清自拍| 欧美日韩国产色站一区二区三区| 欧美激情aⅴ一区二区三区| 亚洲高清电影| 国产精品日韩欧美大师| 久久久久国产精品人| 亚洲裸体在线观看| 久久青青草综合| 亚洲一区二区三区色| 亚洲第一天堂av| 欧美午夜性色大片在线观看| 性色av香蕉一区二区| 亚洲大胆女人| 国产日韩精品一区二区浪潮av| 久久久久成人网| 亚洲永久在线| aa成人免费视频| 一本色道综合亚洲| 亚洲精品久久久久久一区二区| 久久中文字幕一区| 久久激情综合网| 久久精品五月| 欧美一区二区在线观看| 亚洲欧美日产图| 一本大道av伊人久久综合| 亚洲日本va午夜在线电影| 精品二区视频| 尤物在线观看一区| 伊人春色精品| 亚洲欧洲精品一区二区三区 | 亚洲高清激情| 久久永久免费| 亚洲国产国产亚洲一二三| 欧美激情视频在线播放| 欧美成人精品三级在线观看| 久久精品视频免费观看| 久久频这里精品99香蕉| 欧美成人xxx| 一本一本久久| 久久久久久久久久久一区 | 欧美日韩妖精视频| 欧美日韩精品欧美日韩精品一| 欧美日本亚洲视频| 国产乱肥老妇国产一区二 | 欧美香蕉视频| 国产一级一区二区| 99精品欧美一区二区三区综合在线| 日韩亚洲视频在线| 久久爱另类一区二区小说| 久久久久在线| 亚洲深爱激情| 久久综合久久久久88| 国产精品久久久久99| 激情六月综合| 午夜在线一区二区| 91久久精品国产91久久性色| 久久国产精品久久国产精品 | 欧美伊人久久| 亚洲大胆av| 久久久噜噜噜久久人人看| 欧美天堂在线观看| 99精品国产高清一区二区| 免费在线看成人av| 久久久久久久高潮| 在线看日韩欧美| 欧美不卡视频一区发布| 久久婷婷激情| 亚洲国产一区二区精品专区| 欧美国产精品v| 欧美日韩一区二区三区四区五区| 欧美欧美全黄| 国产网站欧美日韩免费精品在线观看 | 在线色欧美三级视频| 性一交一乱一区二区洋洋av| 六十路精品视频| 欧美成人按摩| 99在线观看免费视频精品观看| 欧美日韩久久不卡| 国产中文一区二区| 欧美激情在线播放| 狠狠久久亚洲欧美| 久久国产一区| 久久免费视频一区| 亚洲裸体俱乐部裸体舞表演av| 欧美成人午夜激情| 欧美性大战久久久久| 毛片一区二区三区| 欧美性做爰毛片| 久久国产乱子精品免费女| 国产视频在线观看一区二区| 欧美高清视频在线| 国产视频久久久久| 午夜激情综合网| 亚洲私拍自拍| 欧美日韩精品一区二区三区| 蜜桃伊人久久| 在线精品一区二区| 香港成人在线视频| 欧美在线欧美在线| 国产精品激情偷乱一区二区∴| 欧美激情性爽国产精品17p| 国产欧美日韩高清| 一区二区三区av| 亚洲视频在线观看一区| 欧美欧美全黄| 亚洲欧美综合v| 久久亚洲色图| 99在线|亚洲一区二区|