﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-beautykingdom-随笔分类-VC_MFC</title><link>http://www.cppblog.com/beautykingdom/category/7618.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 07 Feb 2009 18:27:27 GMT</lastBuildDate><pubDate>Sat, 07 Feb 2009 18:27:27 GMT</pubDate><ttl>60</ttl><item><title>在XP下用vc6调试ISAPI Project&lt;转载加改写&gt;</title><link>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56620.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 19 Jul 2008 10:24:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56620.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/56620.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/56620.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/56620.html</trackback:ping><description><![CDATA[<font face="Courier New">关于ISAPI调试的文章，网上已经有很多。今天之所以还要写这篇文章，原因有三：一是网上关于调试
ISAPI的方法大多数都是在Win2K；二是网上的例子虽然多，大部分都是转载，大部分作者自己从未亲自试过，就直接把别人的东西粘贴过来，往往影响了
网上搜索又误导了其他寻找答案的人；三是网上的例子有些并不详细，有些也不正确，这样不但不能帮助解决问题，还容易把人带入歧途。<br>&nbsp;<br>&nbsp;&nbsp; <br>&nbsp;<br>&nbsp;&nbsp;&nbsp; 今天得了一点空闲，在这里详细写下ISAPI在Xp环境下的调试方法，希望初次接触到ISAPI的程序员们少一些郁闷。<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; 首先我的操作系统环境是Microsoft Windows Xp Professional。我的编译环境是Virsual C++6.0。VC的补丁主要有SP6。<br>&nbsp;<br>接下来按照下面的步骤：<br>1、IIS的目录（根目录、虚拟目录）运行级别改为低（默认为中）<br>控制面板-&gt;管理工具-&gt;Internet信息服务。在默认站点上单击右键-&gt;属性-&gt;主目录（标签）-&gt;应用程序保护(N)，将中(共用)改为低(IIS进程)。执行权限改为&#8220;教本和可执行文件&#8221;。<br>用同样的方法修改你新建的虚拟目录的运行级别。<br>&nbsp;<br>2、修改本地安全策略属性<br>控制面板-&gt;管理工具-&gt;本地安全策略-&gt;本地策略-&gt;用户权利指派。<br>a、
找到&#8220;以操作系统方式操作&#8221;，双击或者右键选属性，弹出对话框后，点&#8220;添加用户或组&#8221;按钮，在输入文字区域中输入管理员帐户（又称中超级用户），&#8220;检查名
称&#8221;，&#8220;确定&#8221;添加。比如我现在登陆的帐号是Guyue，&#8220;检查帐号&#8221;之后就出现A7B4931A85554A0\Guyue，
A7B4931A85554A0是我的计算机名称，Guyue是当前登陆帐户，是除Administrator之外的我的管理员帐户。&#8220;确定&#8221;添加。<br>b、找到&#8220;允许计算机和用户帐户被信任以便于委托&#8221;，照a的方法添加管理员帐户。<br>注：这里我没有加用户，直接用的管理员用户。<br>&nbsp;<br>3、打开VC6.0，不需要打开任何工程。<br>菜单栏[Build]-&gt;[Start Debug]-&gt;Attach To Process<br>勾选&#8220;Show System Process&#8221;，找到inetinfo,按OK键添加到该进程。<br>在菜单栏[Project]-&gt;[Settings]或者直接按快捷键Alt+F7。<br>会
看到一个General和一个Debug标签，选择Debug标签。Category下拉列中有两个选项，General和Additional
DLLs，选择Additional DLLs。在Modules中加入你要调试的DLL，勾选Try to locate others
DLLs，按OK确定保存。<br><br>4、打开你的ISAPI工程中的一个CPP文件，看能不能设置断点，如果不能，按shift+F5键退出调试状态。进
入下一步。如果退出之后继续[Build]-&gt;[Start Debug]-&gt;Attach To
Process，这个时候会提示，该工程不包含任何调试信息。如果能设置断点，则直接进入第六步。<br><font face="Courier New">注：这一步没有成功，</font>无法attach to process，点了按钮以后process list还是空的。我是用<br>msdev -p &lt;process ID&gt;生成的一个VC6环境，在运行IE后会在异常抛出位置停止。<br>&nbsp;<br>5、打开你的ISAPI工程中，确定你的编译状态为Debug状态，确定你Link（输出）的DLL和你在第三步Modules中保存的DLL为同一个文件。Rebuild一下。<br>&nbsp;<br>6、菜单栏[Build]-&gt;[Start Debug]-&gt;Attach To Process<br>勾
选&#8220;Show System
Process&#8221;，找到inetinfo,按OK键附加到inetinfo进程。打开ISAPI工程中的一个CPP文件，最好是程序的入口文件，在程序的
入口处设置断点，比如我设置的就是CIsapiWtExtension::InitInstance(...)和DWORD
CIsapiWtExtension::HttpExtensionProc(...)程序一旦开始运行，马上就可以在这里截获。<br>注：既然步骤4里看不到process list，断点设置自然也就不管用了。 <br>&nbsp;<br>7、打开IE，打开你调用该DLL的站点，发出IE请求，VC应该就会在你设置断点的地方拦截到这个请求对当前DLL的操作了。</font><br>
注：正如我在步骤4中讲到的那样，程序在异常位置会停住，可以看到函数的调用顺序；再就是有个小trick，可以加个ASSERT在异常附近位置，这样程序就可以停止在那儿，这样也就可以使用断点了。 <br><br> <img src ="http://www.cppblog.com/beautykingdom/aggbug/56620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2008-07-19 18:24 <a href="http://www.cppblog.com/beautykingdom/archive/2008/07/19/56620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>仿真VC++提供的关键字__uuidof&lt;转&gt;</title><link>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56604.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 19 Jul 2008 08:01:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56604.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/56604.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56604.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/56604.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/56604.html</trackback:ping><description><![CDATA[这个技巧不是针对VC++ 6.0缺陷的，而是针对VC++扩展语法的。这个技巧的来由，是为了某些希望有一天有可能要脱离Visual
C++环境进行开发的人员。为了脱离VC++，你需要谨慎使用它的所有扩展语法。例如本文讨论的__uuidof。我们先来看看一个例子：
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Class;   <br>    struct __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BB")) Interface;   <br>        <br>    void test()   <br>    {   <br>        CLSID clsid=__uuidof(Class);   <br>        IID iid=__uuidof(Interface);   <br>        ...   <br>    }</pre>
<br></div>
<p><br>　　这比起你以前定义uuid的方法简单多了吧？可惜，这样好用的东西，它只在VC++中提供。不过没有关系，我们这里介绍一个技巧，可以
让你在几乎所有C++编译器中都可以这样方便的使用__uuidof。这里没有说是所有，是因为我们使用了模板特化技术，可能存在一些比较&#8220;古老&#8221;的
C++编译器，不支持该特性。
</p>
<p>　　也许你已经迫不及待了。好，让我们来看看：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    #include &lt;string&gt;   <br>    #include &lt;cassert&gt;   <br>        <br>    inline STDMETHODIMP_(GUID) GUIDFromString(LPOLESTR lpsz)   <br>    {   <br>       HRESULT hr;   <br>       GUID guid;   <br>       if (lpsz[0]=='{')   <br>       {  <br>            hr=CLSIDFromString(lpsz,&amp;guid);  <br>        }  <br>        else  <br>        {  <br>            std::basic_string&lt;OLECHAR&gt; strGuid;  <br>            strGuid.append(1,'{');  <br>            strGuid.append(lpsz);  <br>            strGuid.append(1,'}');  <br>            hr = CLSIDFromString((LPOLESTR)strGuid.c_str(),&amp;guid);  <br>        }  <br>        assert(hr==S_OK);  <br>        return guid;  <br>    }  <br>       <br>    template &lt;class Class&gt;  <br>    struct _UuidTraits {  <br>    };  <br>       <br>    #define _DEFINE_UUID(Class,uuid)                                    \  <br>        template &lt;&gt;                                                     \  <br>    struct _UuidTraits&lt;Class&gt;{                                          \  <br>        static const GUID&amp; Guid(){                                      \  <br>        static GUID guid=GUIDFromString(L## uuid);                      \  <br>        return guid;                                                    \  <br>    }                                                                   \  <br>    }  <br>       <br>    #define __uuidof(Class)   _UuidTraits&lt;Class&gt;::Guid()  <br>       <br>    #define DEFINE_CLSID(Class,guid)                                    \  <br>    class Class;                                                        \  <br>        _DEFINE_UUID(Class,guid)  <br>       <br>    #define DEFINE_IID(Interface,iid)                                   \  <br>    struct Interface;                                                   \  <br>        _DEFINE_UUID(Interface,iid)</pre>
<br></div>
<pre><br>　　这样一来，就已经模拟出一个__uuidof关键字。我们可以很方便进行uuid的定义。举例如下：</pre>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    void test()   <br>    {   <br>        CLSID clsid=__uuidof(Class);   <br>        IID iid=__uuidof(Interface);   <br>        ...   <br>    }　　</pre>
<br></div>
<p><br>　　在VC++中，为了与其他编译器以相同的方式来进行uuid的定义，我们不直接使用__declspec(uuid)，而是也定义DEFINE_CLSID, DEFINE_IID宏：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    #define DEFINE_CLSID(Class,clsid)           \   <br>        class __declspec(uuid(clsid)) Class   <br>        <br>    #define DEFINE_IID(Interface,iid)           \   <br>        struct __declspec(uuid(iid)) Interface</pre>
<br></div>
<p><br>　　这样一来，我们已经在所有包含VC++在内的支持模板特化技术的编译器中，提供了__uuidof关键字。通过它可以进一步简化你在C++语言中实现COM组件的代价。
</p>
<p>　　附注：关于本文使用的C++模板的特化技术，详细请参阅C++文法方面的书籍，例如《C++ Primer》。其实这个技巧在C++标准库——STL中有一个专门的名字：traits（萃取），你可以在很多介绍STL的书籍中见到相关的介绍。
</p>
<p>　　转注：因为自己以后写的文章需要用到类似的技巧，因此先搬过来放这。</p>
<br><img src ="http://www.cppblog.com/beautykingdom/aggbug/56604.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2008-07-19 16:01 <a href="http://www.cppblog.com/beautykingdom/archive/2008/07/19/56604.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>更好地仿真VC++关键字__uuidof</title><link>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56602.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 19 Jul 2008 06:03:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56602.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/56602.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56602.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/56602.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/56602.html</trackback:ping><description><![CDATA[出处　<a  href="http://www.cppblog.com/cexer/archive/2008/07/05/55419.html">http://www.cppblog.com/cexer/archive/2008/07/05/55419.html</a> <br><br>
世界上有个叫__uuidof的关键字。这是一个家喻户晓且其被广泛使用的关键字，几乎可以说，有COM程序员的地方，就有它
__uuidof的存在。其很好很强大的程度是人所共见的，夸张一点比喻：离开它的COM程序员，就像失去了点火器的火箭，虽然可以人工点火，但是不安全
且无效率。
<p>　　不过很多人并不知道，这其实是一个编译器扩展关键字，提供了此关键字的仅VC一家别无它店。幸运的是，强大的C++让我们能够轻易仿真出这个关键字的大部分功能。 </p>
<p>　　网上能够找到一种仿真的方法，见<a  href="http://www.cppblog.com/cexer/archive/2008/07/05/55418.html" target="_blank">许式伟:《仿真VC++提供的关键字__uuidof》</a>。该方法的实现是：特化模板类的成员函数，然后运行时调用函数根据UUID字符串产生出UUID，由于是生成于运行时，所以它无可避免地有两个缺点： </p>
<ul>
    <li>存在运行时消耗。  </li>
    <li>无法作为非类型模板参数传递给模板。 </li>
</ul>
<p>　　那些整天流着口水追求效率的C++程序员们，是不能忍受任何不必要的运行时消耗的。对于第二点，VC的关键字__uuidof取出来的UUID
是能够作为非类型模板参数传递的，ATL中就大量地使用了这样的参数传递形式，所以目前的这种实现功能有限，仿真度还不够高。 </p>
<p>　　其实只要能让它能够编译期决定UUID的值，那么这两个问题就迎刃而解了。而这是肯定可以实现的，并且很简单。我曾经在自己写的一个COM库里实现过这样的方法，虽然那个库已经不知丢到哪里去了，不过那个方法还记得。 </p>
<p>　　解决的途径还是离不开模板特化。类的成员包括成员函数和成员变量，函数是运行时作用的，然而static const的成员变量可以是编译期就决定。所以解决的方法就在眼前了：特化模板的成员变量。 </p>
<p>　　以下是我的实现方法。 </p>
<p>　　先定义一个类模板，它有一个static const ,UUID类型的成员变量：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;   <br>    <span style="color: #0000ff;">struct</span> _uuid_of_impl   <br>    {   <br>        <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> UUID id;   <br>    };   <br>    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;   <br>    <span style="color: #0000ff;">const</span> UUID _uuid_of_impl&lt;T&gt;::id=GUID_NULL;</pre>
<br></div>
<p>　　有了这个简单的东西就好办了，只需要针对某个接口特它的成员变量就行了，如：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">template</span>&lt;&gt;    <br>    <span style="color: #0000ff;">const</span> UUID _uuid_of_impl&lt;IUnknown&gt;::id=IID_IUnknown;   <br>        <br>    <span style="color: #0000ff;">template</span>&lt;&gt;   <br>    <span style="color: #0000ff;">const</span> UUID _uuid_of_impl&lt;IDispatch&gt;::id=IID_IDispatch;</pre>
<br></div>
<p><br>　　然后我们就可以这样取得接口的UUID：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    IID IunknownID=_uuid_of_impl&lt;IUnknown&gt;::id;   <br>    IID IdispatchID=_uuid_of_impl&lt;IDispatch&gt;::id;</pre>
<br></div>
<p><br>　　作为非类型模板参数传递：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">const</span> IID* t_iid&gt;   <br>    <span style="color: #0000ff;">struct</span> __uuid_of_test   <br>    {   <br>        __uuid_of_test()   <br>        {}   <br>        <br>        <span style="color: #0000ff;">void</span> test()   <br>        {   <br>            t_iid;  <br>         }  <br>     };  <br>        <br>     __uuid_of_test&lt;&amp;(_uuid_of_impl&lt;IDispatch&gt;::id) &gt; obj;</pre>
<br></div>
<p><br>　　不过现在这种实现还有一些问题，看以下代码：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    IID ITypelibID=_uuid_of_impl&lt;ITypeLib&gt;::id;</pre>
<br></div>
<p><br>　　注意我们并没有事先对模板__uuid_of_impl特化ITypeLib的版本。但是以上语句却能够编译通过，在运行时，
__uuid_of_impl&lt;ITypeLib&gt;的值将会是错误的值GUID_NULL。这是因为，我们定义模板的时候，同时在模板外定义
了模板的静态成员变量并赋值为GUID_NULL，所以没有用特化的方法定义UUID的接口，都将使用GUID_NULL这个通用值。这当然不是我们想要
的。所以我们想在没有定义UUID的时候让编译器警告我们，要达到这样的效果只需要去掉上面那句：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;   <br>    <span style="color: #0000ff;">const</span> UUID _uuid_of_impl&lt;T&gt;::id=GUID_NULL;</pre>
<br></div>
<p><br>　　现在再进行编译，编译器会告诉你，有一个无法解析的符号。根据编译器提供的相关信息，很容易就能确定问题所在。这样能够在编译期极大地减小安全隐患。 </p>
<p>　　最后加上我们定义的几个宏，这是最后的全部实现：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;   <br>    <span style="color: #0000ff;">struct</span> _uuid_of_impl   <br>    {   <br>        <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">const</span> UUID id;   <br>    };   <br>        <br>    <span style="color: #cc6633;">#define</span> uuid_of(x)    _uuid_of_impl&lt;x&gt;::id   <br>    <span style="color: #cc6633;">#define</span> DEFINE_UUID(x,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)    \   <br>        <span style="color: #0000ff;">template</span>&lt;&gt;    \  <br>         <span style="color: #0000ff;">const</span> UUID _uuid_of_impl&lt;x&gt;::id={l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}</pre>
<br></div>
<p><br>　　用以下代码测试通过：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">struct</span> ITest{};   <br>        <br>    DEFINE_UUID(ITest,0x96289151,0xf059,0x4049,0x88,0x19,0x61,0xa6,0xe9,0x79,0xc,0xf1);<br>        <br>    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">const</span> IID* t_iid&gt;   <br>    <span style="color: #0000ff;">struct</span> uuid_of_test   <br>    {   <br>        uuid_of_test(){}   <br>    };  <br>        <br>    <span style="color: #0000ff;">int</span> main()  <br>    {  <br>        IID xxxxID=uuid_of(ITest);  <br>        uuid_of_test&lt;&amp;(uuid_of(ITest))&gt; obj;  <br>        <br>        <span style="color: #0000ff;">return</span> 0;  <br>    }</pre>
<br></div>
<p><br>　　需要注意的是DEFINE_UUID应该在实现文件（*.cpp，*.cxx，&#8230;&#8230;）当中使用。到这里，仍有一些使用方法与VC的关键
字是不一样的，所以仍没做到仿真度100%。不过我相信通过预处理元编程，能够相当程度地逼近它，只是我对预处理元编程不是很了解，所以就不在这里献丑
了。</p><img src ="http://www.cppblog.com/beautykingdom/aggbug/56602.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2008-07-19 14:03 <a href="http://www.cppblog.com/beautykingdom/archive/2008/07/19/56602.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++编译期函数/变量检测技术，仿真VC关键字__if_exists&lt;转&gt;</title><link>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56601.html</link><dc:creator>chatler</dc:creator><author>chatler</author><pubDate>Sat, 19 Jul 2008 05:50:00 GMT</pubDate><guid>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56601.html</guid><wfw:comment>http://www.cppblog.com/beautykingdom/comments/56601.html</wfw:comment><comments>http://www.cppblog.com/beautykingdom/archive/2008/07/19/56601.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/beautykingdom/comments/commentRss/56601.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/beautykingdom/services/trackbacks/56601.html</trackback:ping><description><![CDATA[出处　<a  href="http://www.cppblog.com/cexer/archive/2008/07/06/55484.html" target="_blank">http://www.cppblog.com/cexer/archive/2008/07/06/55484.html</a><br><br>　　VC当中有一个鲜为人知的关键字，除了微软自己的代码，我从未在任何地方看到有人用过它。虽然它的功能很强大，不过除非设计上的问题或是一些无法排除的困难，否则几乎从不会需要用到它的功能。但是有时候，它确实能作为一个最简单的解决方案而让某些设计过程事半功倍。
<p>　　借用 CCTV10《走近科学》的语气：那么这个神秘的关键关键字到底是什么呢？它又实现了什么神奇的功能呢？带着这一连串的疑问，让我们先来看一个具体的例子。</p>
<p>　　我在自己曾经写的一个GUI框架当中，为了实现消息与处理函数自动映射的，就需要求助于这种功能。比如说有一个窗口类，它包含若干消息处理函数和一个消息与处理函数的映射 map：（请无视当中的 show() 和 create() 函数，与主题无关）</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">class</span> Window<br>    {<br>        <span style="color: #0000ff;">typedef</span> UINT _Message;<br>        <span style="color: #0000ff;">typedef</span> LRESULT (Window::*_Handler)(_Message);<br>    <br>        map&lt;_Message,_Handler&gt; m_handlerMap;<br>    <br>    <span style="color: #0000ff;">public</span>:<br>        <span style="color: #0000ff;">bool</span> show();<br>        <span style="color: #0000ff;">bool</span> create();<br>    <br>    <span style="color: #0000ff;">public</span>:<br>        LRESULT onEvent( WindowEvent&lt;WM_CREATE&gt; );<br>        LRESULT onEvent( WindowEvent&lt;WM_DESTROY&gt; );<br>    };</pre>
<br></div>
<p>　　<br>　　我需要利用模板元编程 从 0 到 WM_USER&nbsp; 进行循环检测，检测 Window
类是否存在该消息对应的处理函数。如果消息对应的处理函数存在，那么就将消息与函数的映射放进 m_handlerMap 当中。比如说消息
WM_CREATE，我检测类 Window是否存在 LRESULT onEvent( WindowEvent&lt;WM_CREATE&gt;
)
成员函数，在上例代码中是存在的，于是我将这样一个映射放进m_handlerMap：（真正实现的时候，还要考虑函数的类型。不同类型的函数，是不能直
接装进 map 当中的。不过在这里请无视例子当中涉及的所有类型转换，与主题无关）</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    pair&lt;WM_CREATE,&amp;Window::onEvent&gt;</pre>
<br></div>
<p><br>　　这样就达到了消息自动映射的目的。而不用像MFC一样手写宏去映射。（最后通过努力的确达到了我的目的，我的GUI框架能够进行自动消
息映射了，然而可以预见，由于几千个（0－WM_USER）循环，编译期的速度受到极大影响。所以最终我还是抛弃了这种自动映射实现，而采用了更高效神奇
的方法，这是后话也与本主题无关就先不提）。</p>
<p>　　要实现以上的自动映射功能就引出了这样一个难题：如何编译期检测类的某特定名字的成员是否存在。</p>
<p>　　功能不负有心人，经过爬山涉水翻山越岭，我终于在 MSDN
一个偏远角落里找着了传说当中那个神秘的关键字：__if_exists（其实还有一个 __if_not_exists）。MSDN
当中这样说明：__if_exists
（__if_not_exists）允许你针对某符号的存在与否条件性地执行语句。使用语法：（注意检测的是&#8220;存在性&#8221;，而不是值）<br></p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    __if_exists ( <span style="color: #008000;">/*你要检测存在性的函数或变量的名字*/</span> ) { <br>    　<span style="color: #008000;">//做些有用的事</span><br>    }</pre>
<br></div>
<br>　　MSDN当中的示例代码如下:
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #008000;">// the__if_exists_statement.cpp</span><br>    <span style="color: #008000;">// compile with: /EHsc</span><br>    <span style="color: #cc6633;">#include</span> &lt;iostream&gt;<br>    <br>    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;<br>    <span style="color: #0000ff;">class</span> X : <span style="color: #0000ff;">public</span> T {<br>    <span style="color: #0000ff;">public</span>:<br>       <span style="color: #0000ff;">void</span> Dump() {<br>          std::cout &lt;&lt; <span style="color: #006080;">"In X&lt;T&gt;::Dump()"</span> &lt;&lt; std::endl;<br>    <br>          __if_exists(T::Dump) {<br>             T::Dump();<br>          }<br>    <br>          __if_not_exists(T::Dump) {<br>             std::cout &lt;&lt; <span style="color: #006080;">"T::Dump does not exist"</span> &lt;&lt; std::endl;<br>          }<br>       }   <br>    };<br>    <br>    <span style="color: #0000ff;">class</span> A {<br>    <span style="color: #0000ff;">public</span>:<br>       <span style="color: #0000ff;">void</span> Dump() {<br>          std::cout &lt;&lt; <span style="color: #006080;">"In A::Dump()"</span> &lt;&lt; std::endl;<br>       }<br>    };<br>    <br>    <span style="color: #0000ff;">class</span> B {};<br>    <br>    <span style="color: #0000ff;">bool</span> g_bFlag = true;<br>    <br>    <span style="color: #0000ff;">class</span> C {<br>    <span style="color: #0000ff;">public</span>:<br>       <span style="color: #0000ff;">void</span> f(<span style="color: #0000ff;">int</span>);<br>       <span style="color: #0000ff;">void</span> f(<span style="color: #0000ff;">double</span>);<br>    };<br>    <br>    <span style="color: #0000ff;">int</span> main() { <br>       X&lt;A&gt; x1;<br>       X&lt;B&gt; x2;<br>    <br>       x1.Dump();<br>       x2.Dump();<br>    <br>       __if_exists(::g_bFlag) {<br>          std::cout &lt;&lt; <span style="color: #006080;">"g_bFlag = "</span> &lt;&lt; g_bFlag &lt;&lt; std::endl;<br>       }<br>    <br>       __if_exists(C::f) {<br>          std::cout &lt;&lt; <span style="color: #006080;">"C::f exists"</span> &lt;&lt; std::endl;<br>       }<br>    <br>       <span style="color: #0000ff;">return</span> 0;<br>    }<br>    </pre>
<br></div>
<p><br>　　以上代码的输出如下：（未测试，此输出为MSDN的说明文档当中的）</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    In X&lt;T&gt;::Dump()<br>    In A::Dump()<br>    In X&lt;T&gt;::Dump()<br>    T::Dump does not exist<br>    g_bFlag = 1<br>    C::f exists</pre>
<br></div>
<p><br>　　大概很少人见过这个关键字吧。虽然它们的功能与我的需求是如此的接近，但是面对如此强憾的关键字，我还是只能摇头叹息。我伤心地在文档
里看到说明，__if_exists（__if_not_exists）关键字用于函数的时候，只能根据函数名字进行检测，而会忽略对参数列表的检测，因
此没有对重载函数的分辨能力，而正是我需要的。比如类 Window 有一个函数：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    LRESULT Window::onEvent( WindowEvent&lt;WM_DESTROY&gt; )<br>    {<br>      <span style="color: #008000;">//做些有用的事</span><br>    }</pre>
<br></div>
<p><br>　　我用以下代码来检测 WM_CREATE 消息是否存在处理函数：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">&nbsp;&nbsp;&nbsp; __if_exists(Window::onEvent)<br>　　{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #008000;">//添加消息映射</span><br>&nbsp;&nbsp; }</pre>
<br></div>
<p><br>　　即使 Window 类当中不存在 LRESULT onEvent (
WindowEvent&lt;WM_CREATE&gt; )，以上测试也能通过。这是因为 __if_exists
关键字是不管函数重载的，如果存在一个 onEvent ，那么所有的检测都能通过。这不是我想要的。我需要比 __if_exists
更强憾的检测功能，强憾到能够针对不同参数列表的同名函数（重载函数）做出正确的存在性测试。</p>
<p>　　于是我继续翻山越岭地寻找，从 CSDN 到 MSDN，从 SourceForge 到 CodeProject。要相信那句老话：&#8220;有心人天不负&#8221;。最后我在 CodeProject 上面看到一篇让我醍醐灌顶的文章：</p>
<p>　　<a  href="http://www.codeproject.com/KB/architecture/Detector.aspx" target="_blank">Interface Detection</a> by Alexandre Courpron</p>
<p>　　这篇文章从原理到实现，很详细地说明地一种编译期检测技术，先说明一下，由于VC7.1数千个bug当中的一个，以下技术不能在VC++7.1或更低版本上使用。具体的实现在那篇文章当中说得很详尽了，还是在这儿赘述一下。</p>
<p>　　Alexandre Courpron的实现方式基于C++的这样一个规则：<strong>S</strong>ubstitution <strong>F</strong>ailure <strong>I</strong>s <strong>N</strong>ot <strong>A</strong>n <strong>E</strong>rror
（简称SFINAE）。它的含义我也理解得比较含糊，不过它作用于重载函数的时候，可以这样理解：对于一个函数调用，在匹配函数的过程当中，如果最终能够
有一个函数匹配成功，那么对其余函数的匹配如果失败，编译器也不会视为错误。听起来有些麻烦，看Alexandre Courpron给出的例子：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">struct</span> Test <br>    {<br>        <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">int</span> Type;<br>    };<br>    <br>    <span style="color: #0000ff;">template</span> &lt; <span style="color: #0000ff;">typename</span> T &gt; <br>    <span style="color: #0000ff;">void</span> f(<span style="color: #0000ff;">typename</span> T::Type) {}  <span style="color: #008000;">// definition #1</span><br>    <br>    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt; <br>    <span style="color: #0000ff;">void</span> f(T){}                  <span style="color: #008000;">// definition #2</span><br>    <br>    f&lt;Test&gt;(10); <span style="color: #008000;">//call #1</span><br>    <br>    f&lt;<span style="color: #0000ff;">int</span>&gt;(10);  //call #2</pre>
<br></div>
<p>　　<br>　　对于 call#1 编译器直接匹配 definition#1 成功。对于 call#2，编译器先用 definition#1 匹配 如下：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">void</span> f( <span style="color: #0000ff;">typename</span> <span style="color: #0000ff;">int</span>::Type ) {}</pre>
<br></div>
<p><br>　　这显然是不正确的。不过编译器并没有编译失败报告错误，因为下面的 definition#2 匹配成功，根据 SFINAE的 规则，编译器有权保持沉默 。</p>
<p>　　虽然是个小小的规则，在平时几乎不会注意它。然而在这儿，我们却可以利用它实现编译期检测的强大功能了，一个最简单的示例：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #cc6633;">#include</span> &lt;iostream&gt;<br>    <span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std;<br>    <span style="color: #008000;">//</span><br>    <span style="color: #0000ff;">struct</span> TestClass<br>    {<br>        <span style="color: #0000ff;">void</span> testFun();<br>    };<br>    <br>    <span style="color: #0000ff;">struct</span> Exists { <span style="color: #0000ff;">char</span> x;};  <br>    <span style="color: #0000ff;">struct</span> NotExists    { <span style="color: #0000ff;">char</span> x[2]; }; <br>    <br>    <span style="color: #0000ff;">template</span> &lt;<span style="color: #0000ff;">void</span> (TestClass::*)()&gt;<br>    <span style="color: #0000ff;">struct</span> Param ;<br>    <br>    <span style="color: #0000ff;">template</span> &lt;<span style="color: #0000ff;">class</span> T&gt;<br>    Exists isExists( Param&lt;&amp;T::testFun&gt;* );<br>    <br>    <span style="color: #0000ff;">template</span> &lt;<span style="color: #0000ff;">class</span> T&gt;<br>    NotExists isExists( ... );<br>    <span style="color: #008000;">//</span><br>    <span style="color: #0000ff;">int</span> main()<br>    {<br>        cout&lt;&lt;<span style="color: #0000ff;">sizeof</span>(isExists&lt;TestClass&gt;(0))&lt;&lt;endl;<br>    }</pre>
<br></div>
<p><br>　　上面的代码会输出 １。说明一下检测的过程：</p>
<ol>
    <li>编译器遇到 isExists&lt;TestClass&gt;(0) 这一句，会去匹配 isExists 的两个重载函数。不定长的参数优先级更低，因此先匹配第一个函数。
    </li>
    <li>第一个函数参数类型为 Param&lt;&amp;T::testFun&gt;*，在这里是 Param&lt;&amp;TestClass::testFun&gt;，编译器在匹配这个参数类型的时候会尝试实例化模板类 Param。
    </li>
    <li>编
    译器尝试用 &amp;TestClass::testFun 去实例化 Param，因为 TestClass 确实存在一个 void
    (TestClass::*)() 类型，且名为 testFun 的成员函数。所以 Param 的实例化成功，因此参数匹配成功。 </li>
    <li>匹配第一个函数成功。编译器决定 isExists&lt;TestClass&gt;(0) 这一句调用就是调用的第一个函数。
    </li>
    <li>因为第一个函数返回的类型为 Exists，用 sizeof 取大小就是 1。 </li>
</ol>
<p>　　如果是我们把 TestClass 的定义修改为：（仅把函数的参数类型改为 int ）</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    <span style="color: #0000ff;">struct</span> TestClass<br>    {<br>        <span style="color: #0000ff;">void</span> testFun(<span style="color: #0000ff;">int</span>);<br>    };</pre>
<br></div>
<p><br>　　这一次代码会输出 ２。因为在第３步的时候，由于 TestClass 没有类型为 void
(TestClass::*)()，且名为 testFun 的函数，所以实例化 Param
会失败，因此匹配第一个函数失败。然后编译器去匹配第二个函数。因为其参数类型是任意的，自然会匹配成功。结果会输出 2。</p>
<p>　　当然这只是个最简单的示例，通过模板包装类。可以实现更灵活更强大的功能。比如回到那个自动消息映射的例子，用以下代码就能够实现了：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<p>    <span style="color: #008000;">//c++std</span><br>    <span style="color: #cc6633;">#include</span> &lt;iostream&gt;<br>    <span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std;</p>
<br>
<p><br><br>    <span style="color: #008000;">//windows</span><br>    <span style="color: #cc6633;">#include</span> &lt;windows.h&gt;</p>
<br>
<p><br>    <span style="color: #008000;">//detector</span><br>    <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> TWindow,UINT t_msg&gt;<br>    <span style="color: #0000ff;">struct</span> MessageHandlerDetector<br>    {<br>        <span style="color: #0000ff;">typedef</span> WindowEvent&lt;t_msg&gt; _Event;<br>    <br>        <span style="color: #0000ff;">struct</span> Exists {<span style="color: #0000ff;">char</span> x;};<br>        <span style="color: #0000ff;">struct</span> NotExists {<span style="color: #0000ff;">char</span> x[2];};<br>    <br>        <span style="color: #0000ff;">template</span>&lt;LRESULT (TWindow::*)(_Event)&gt;<br>        <span style="color: #0000ff;">struct</span> Param;<br>    <br>        <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;<br>        <span style="color: #0000ff;">static</span> Exists detect( Param&lt;&amp;T::onEvent&gt;* );<br>    <br>        <span style="color: #0000ff;">template</span>&lt;<span style="color: #0000ff;">typename</span> T&gt;<br>        <span style="color: #0000ff;">static</span> NotExists detect( ... );<br>    <br>    <span style="color: #0000ff;">public</span>:<br>        <span style="color: #0000ff;">enum</span>{isExists=<span style="color: #0000ff;">sizeof</span>(detect&lt;TWindow&gt;(0))==<span style="color: #0000ff;">sizeof</span>(Exists)};<br>    };<br>    <br>    <span style="color: #008000;">//test classes</span><br>    <span style="color: #0000ff;">struct</span> Window<br>    {<br>        LRESULT onEvent( WindowEvent&lt;WM_CREATE&gt; );<br>    };<br>    <br>    <span style="color: #0000ff;">struct</span> Button<br>    {<br>        LRESULT onEvent( WindowEvent&lt;WM_DESTROY&gt; );<br>    };<br>    <br>    <span style="color: #008000;">//main</span><br>    <span style="color: #0000ff;">int</span> main()<br>    { <br>        cout&lt;&lt;MessageHandlerDetector&lt;Window,WM_CREATE&gt;::isExists&lt;&lt;endl;<br>        cout&lt;&lt;MessageHandlerDetector&lt;Window,WM_DESTROY&gt;::isExists&lt;&lt;endl;<br>        cout&lt;&lt;MessageHandlerDetector&lt;Button,WM_CREATE&gt;::isExists&lt;&lt;endl;<br>        cout&lt;&lt;MessageHandlerDetector&lt;Button,WM_DESTROY&gt;::isExists&lt;&lt;endl;<br>    <br>        <span style="color: #0000ff;">return</span> 0;<br>    }<br></p>
<br></pre>
<br></div>
<p><br>　　以上代码会输出：</p>
<div id="codeSnippetWrapper" style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; font-size: 9pt; width: 97.5%; cursor: text; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">
<pre id="codeSnippet" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 9pt; width: 100%; color: black; line-height: 12pt; font-family: 'Courier New',courier,monospace; background-color: #e6e6e6;">    1<br>    0<br>    0<br>    1</pre>
<br></div>
<p><br>　　以上的示例代码再加上模板元编程，可以很轻易地实现消息的自动映射，具体实现这个已不在本贴的讨论范围并且这种自动映射的实现，太过复杂，在编译期没有效率，且不够灵活。不过在消息映射机制上来说，已称得上是一种革命性的尝试。</p>
<p>　　在说完了这所有一切之后，再告诉你一个我最近才知道的秘密（不准笑我孤陋寡闻）：其实 boost 库当中已有相关功能的 MPL&nbsp; 工具存在，叫做 has_xxx。</p>
<p>　　源文件：&lt;boost\mpl\has_xxx.hpp&gt;</p>
<p>　　文档：<a  href="http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html" target="_blank">http://www.boost.org/doc/libs/1_35_0/libs/mpl/doc/refmanual/has-xxx-trait-def.html</a>。</p><img src ="http://www.cppblog.com/beautykingdom/aggbug/56601.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/beautykingdom/" target="_blank">chatler</a> 2008-07-19 13:50 <a href="http://www.cppblog.com/beautykingdom/archive/2008/07/19/56601.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>