﻿<?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++博客-溪流漫话-随笔分类-C++</title><link>http://www.cppblog.com/Streamlet/category/11878.html</link><description>荒废中，求警醒~</description><language>zh-cn</language><lastBuildDate>Sat, 05 Nov 2022 18:05:23 GMT</lastBuildDate><pubDate>Sat, 05 Nov 2022 18:05:23 GMT</pubDate><ttl>60</ttl><item><title>建立一个简单干净的 gn+ninja 工具链</title><link>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sat, 05 Nov 2022 18:05:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/229483.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/229483.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/229483.html</trackback:ping><description><![CDATA[
<h2>背景</h2>
<p>事情的起因是，想找个跨 Windows 和 Mac 的构建方案。第一考虑自然是 CMake，毕竟基本上是事实标准了。</p>
<p>但是研究了一下 Modern CMake，也就是以 target 为核心的理念。但发现看了好几天文档，也折腾出了可用的东西，但仍然是没梳理清楚什么理念、原理。然后 CMake 本身语法就很复杂，再加上搞 target 一套概念，要给 target 设置各种属性之类的，有点强行 OOP 的感觉……但其实我们只是需要一个 include_dir 和 lib_dir 而已，其他都是浮云~</p>
<p>但如果退回到传统模式，不用 Modern 概念呢，好像可以将就，但第一不去用一个工具的最新模式，好像有点不上进的感觉（python 2 除外）；第二，CMake 的两大痛点——语法特立独行、文档晦涩难懂——还是让人有点不爽。</p>
<p>那跳出来看别的选择呢？目前相对成熟的也只有 Google 的 gn+ninja 方案了。gn 这套东西在 Chromium 里是完全配置好的，用起来还算顺手，但要是独立拿出来呢，就没那么便宜了。关键是它的 toolchain 是要自己定义的。</p>
<p>之前还在公司搞客户端的时候，大家就从 Chromium 里面把 build、build_overrides 等等东西全部拷出来，好家伙，几百 MB 甚至上 G。但是公司里嘛，没人管干不干净，怎么快怎么来。后来又看到 Google 自家的 Crashpad 里面也用了这套构建，但工具链被简化了一下，叫 mini_chromium。这个比 Chromium 里的小多了，是可以拿过来直接用的，缺少一些配置可以自己加。但是呢，像我们这种洁癖，仍然是受不鸟的。所以呢，我们要干干净净的建立一套工具链。</p>
<h2>构建系统安装</h2>
<p>首先，我们明确定位。gn 和 ninja 都是开发机上需要预装的，不是软件提供的。Chromium 的搞法是自己提供，gn 的文档也说让开发者提供工具。但这套思路跟传统的理念是冲突的。同时，自己安装工具成本是比较低的：</p>
<ul>
<li>linux
<ul>
<li>ninja 在主流包管理系统里已经有了，包名可能是 ninja 或 ninja-build，直接安装就可以</li>
<li>gn 在部分包管理系统有，尝试包名 gn 或 gn-build 等，没有的话可以下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest">二进制版本</a>，或者从源代码自行编译</li>
</ul>
</li>
<li>mac
<ul>
<li>ninja 在 brew 里包名叫 ninja，在 MacPorts 里包名叫 ninja-build</li>
<li>gn 在 brew 里没有，可以下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest">二进制版本</a>；在 MacPorts 里叫 gn-devel</li>
</ul>
</li>
<li>win
<ul>
<li>ninja 可以在 <a href="https://github.com/ninja-build/ninja/releases">GitHub</a> 下载二进制版本，gn 可以在 gn 官网下载<a href="https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest">二进制版本</a></li>
</ul>
</li>
</ul>
<p>自己下载的设置到 PATH，测试 <code>gn --version</code> 以及 <code>ninja --version</code>，能运行即可</p>
<h2>目标</h2>
<p>希望做到提供一个 git repo，使用者 clone 到自己项目的 build 目录，然后使用者只要在 .gn 文件里配置</p>
<pre><code class="language-gn">buildconfig = &quot;//build/BUILDCONFIG.gn&quot;
</code></pre>
<p>就可以使用我们提供的工具链，在 PC 三端进行构建。</p>
<p>使用者的唯一负担就是编写自己的 BUILD.gn</p>
<h2>工具链搭建</h2>
<p>首先我们看 gn 的文档，以及它的例程 simple_build 里的工具链配置：</p>
<p>https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn</p>
<p>这个是可以直接用的，只不过只有 linux 端（当然 mac 也能用）。我们再结合 chrome 里的工具链配置，进行一些完善。</p>
<h3>基础概念</h3>
<p>首先我们了解 gn 体系需要的最小配置是什么。</p>
<p>第一，它需要在根目录写一个 .gn 文件，在里面定义 buildconfig，指到另一个文件，一般是</p>
<pre><code class="language-gn">buildconfig = &quot;//build/BUILDCONFIG.gn&quot;
</code></pre>
<p>第二、BUILDCONFIG.gn 里面需要设置默认工具链，也就是写一行</p>
<pre><code class="language-gn">set_default_toolchain(&quot;//build/toolchain:gcc&quot;)
</code></pre>
<p>第三、定义工具链，如上例的 //build/toolchain:gcc。</p>
<p>需要在 build/toolchain 下建立 BUILD.gn 文件，内容是</p>
<pre><code>toolchain(&quot;gcc&quot;) {
	# ...
}
</code></pre>
<p>最后在 toolchain 里定义各种 tool。</p>
<h3>工具链中的工具</h3>
<p>这部分文档在这里：https://gn.googlesource.com/gn/+/main/docs/reference.md#func_tool</p>
<p>简单复述一下，可被定义的工具有：</p>
<ul>
<li>编译工具:<br />
&quot;cc&quot;: C 编译器<br />
&quot;cxx&quot;: C++ 编译器<br />
&quot;cxx_module&quot;: 支持 module 的 C++ 编译器<br />
&quot;objc&quot;: Objective C 编译器<br />
&quot;objcxx&quot;: Objective C++ 编译器<br />
&quot;rc&quot;: Windows 资源脚本编译器<br />
&quot;asm&quot;: 汇编器<br />
&quot;swift&quot;: Swift 编译器</li>
<li>链接工具:<br />
&quot;alink&quot;: 静态库链接器<br />
&quot;solink&quot;: 动态库链接器<br />
&quot;link&quot;: 可执行文件链接器</li>
</ul>
<p>（其他的就先不看了）</p>
<p>我们来看一下 https://gn.googlesource.com/gn/+/HEAD/examples/simple_build/build/toolchain/BUILD.gn 的一些关键配置：</p>
<pre><code class="language-gn">toolchain(&quot;gcc&quot;) {
  tool(&quot;cc&quot;) {
    command = &quot;gcc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}&quot;
    outputs = [ &quot;{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o&quot; ]
    # ...
  }
  tool(&quot;cxx&quot;) {
    command = &quot;g++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}&quot;
    outputs = [ &quot;{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o&quot; ]
    # ...
  }
  tool(&quot;alink&quot;) {
    command = &quot;rm -f {{output}} &amp;&amp; ar rcs {{output}} {{inputs}}&quot;
    outputs = [ &quot;{{target_out_dir}}/{{target_output_name}}{{output_extension}}&quot; ]
    # ...
  }
  tool(&quot;solink&quot;) {
    command = &quot;g++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile&quot;
    outputs = [ sofile ]
    # ...
  }
  tool(&quot;link&quot;) {
    command = &quot;g++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}&quot;
    outputs = [ outfile ]
    # ...
  }
  tool(&quot;stamp&quot;) {
    command = &quot;touch {{output}}&quot;
  }
  tool(&quot;copy&quot;) {
    command = &quot;cp -af {{source}} {{output}}&quot;
  }
}
</code></pre>
<p>可以看到，cc 和 cxx 执行 command 后，生成 .o 文件，然后这些 .o 文件可以作为 alink、solink、link 的 inputs，被它们 command 继续使用，最后输出静态库、动态库以及可执行文件。</p>
<p>其余属性可以查文档了解含义。</p>
<h3>对比 Chromium 中的配置</h3>
<h4>Linux</h4>
<p>主要配置在这里：https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/gcc_toolchain.gni</p>
<p>也是 gcc 的，与 simple_build 里的大同小异，没有特别的。</p>
<h4>Mac</h4>
<p>主要配置在这里：https://source.chromium.org/chromium/chromium/src/+/main:build/toolchain/apple/toolchain.gni</p>
<p>区别有：</p>
<ul>
<li>用 clang 系列编译工具，而不是 gcc</li>
<li>alink 不是用 ar，而使用 libtool</li>
<li>solink 的默认扩展名改成了 dylib</li>
<li>用了一个 linker_driver.py 来支持生成 dSYM，在里面调用了 dsymutil 和 strip</li>
</ul>
<h4>Win</h4>
<ul>
<li>编译用 cl，静态库链接用 lib，动态库和可执行文件的链接用 link</li>
<li>lib_switch = &quot;&quot;，lib_dir_switch = &quot;/LIBPATH:&quot;；前两者 lib_switch = &quot;-l&quot;，lib_dir_switch = &quot;-L&quot;</li>
</ul>
<h3>建立我们的工具链</h3>
<p>基本上是根据上面分析的要点配置，最终结果在此：https://github.com/Streamlet/gn_toolchain</p>
<p>新增的一些差异有：</p>
<ul>
<li>
<p>增加全局参数 is_debug，可以在 <code>gn gen out --args=&quot;is_debug=true&quot;</code>传入。默认 is_debug 为 false，开启所有优化。</p>
</li>
<li>
<p>mac 下生成 dSYM 不使用 python 脚本，直接是 <code>$ld ... &amp;&amp; dsymutil ... &amp;&amp; strip</code></p>
</li>
<li>
<p>mac 下加了一个 template：app_bundle，用来生成 xxx.app，主要配置来自于 create_bundle 文档里的例子</p>
</li>
<li>
<p>win 下增加了一些配置集</p>
<ul>
<li>
<p>动态/静态链接 CRT：//build/config/win:console_subsystem、//build/config/win:static_runtime</p>
</li>
<li>
<p>控制台程序、Win32 程序：//build/config/win:console_subsystem、//build/config/win:windows_subsystem</p>
<p>这个其实一般情况下用不着，只要入口函数是 main/WinMain，link 默认就是控制台程序/Win32 程序</p>
</li>
<li>
<p>XP 支持：//build/config/win:console_subsystem_xp、//build/config/win:windows_subsystem_xp</p>
<p>具体实现是链接参数加 /SUBSYSTEM:CONSOLE,5.01 或 /SUBSYSTEM:WINDOWS,5.01。关键是后面的版本号 5.01，为了加版本号则必须指定子系统名称，所以分了 console_subsystem_xp 和 windows_subsystem_xp。又，xp 这里提供了两个 subsystem 的配置集，非 xp 也提供两个。</p>
<p>但是我们没有加 _WIN32_WINNT=0x0501、WINVER=0x0501、_USING_V110_SDK71_，也没有指定必须使用 7.0 版本的 SDK，这些都是非必须的，只要不用到 XP 以后添加的 API 即可。使用者可以在自己的 target 里面定义这些宏。</p>
</li>
</ul>
</li>
</ul>
<h2>使用案例</h2>
<p>提供一个使用案例：https://github.com/Streamlet/gn_toolchain_sample</p>
<p>因为它以 git submodule 形式引用了 https://github.com/Streamlet/gn_toolchain，所以 git clone 以后，需要 <code>git submodule update --init</code>一下。</p>
<p>然后在根目录执行：（确保 gn 和 ninja 已经在 PATH 中）</p>
<pre><code class="language-sh">gn gen out
ninja -C out
</code></pre>
<p>即可。</p>
<p>Mac 下会额外生成一个 objc 项目 objc_console_application 以及一个 app_bundle：ns_application.app。</p>
<p>Win 会额外生成一个 Win32 项目 win32_application。</p>
<p>Win 下需要先执行一下 Visual Studio 带的命令行环境，如 VS 2022 Community 的 “x64 Native Tools Command Prompt for VS 2022”，cl 等工具才会可用。</p>
<p>如果要测试 XP（32位），用“x86 Native Tools Command Prompt for VS 2022”进入，CD 到项目目录，执行：</p>
<pre><code class="language-gn">gn gen out --args=&quot;target_cpu=\&quot;x86\&quot;&quot;
ninja -C out
</code></pre>
<h2>总结</h2>
<p>我们只用几十 KB 的大小完成了跨端支持，是很轻量的一个配置。如果您觉得实用并认可这种方式，欢迎一起来维护、完善。</p>
<img src ="http://www.cppblog.com/Streamlet/aggbug/229483.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2022-11-06 02:05 <a href="http://www.cppblog.com/Streamlet/archive/2022/11/06/229483.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>微软拼音长句模式恢复工具支持Win10 1803</title><link>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 Sep 2020 05:53:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/217462.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/217462.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/217462.html</trackback:ping><description><![CDATA[<p>4月份就有人留言旧微软拼音恢复工具不支持Win10 1803了，我自己也遇到了，但因为没时间搞，勉为其难使用了词组模式的微软拼音几个月，终于在八月份抽个空研究了下，解决了。</p> <p>这次是因为傻逼大微软改了 System32\IME\shared 里的东西，导致旧系统拷过来的文件与 System32\IME\shared 的东西不兼容了。解决方式很暴力：从以前的版本复制 System32\IME\shared 过来。</p> <p>下载：<a href="https://www.streamlet.org/software/mspyforever/">https://www.streamlet.org/software/mspyforever/</a></p> <p>（原发于 GitHub Pages，2018-10-13 13:36:04）</p><img src ="http://www.cppblog.com/Streamlet/aggbug/217462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2020-09-20 13:53 <a href="http://www.cppblog.com/Streamlet/archive/2020/09/20/217462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发布个工具，一键恢复Win8/8.1中的微软拼音长句模式（新体验模式）</title><link>http://www.cppblog.com/Streamlet/archive/2014/03/26/206335.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Tue, 25 Mar 2014 17:10:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2014/03/26/206335.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/206335.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2014/03/26/206335.html#Feedback</comments><slash:comments>24</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/206335.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/206335.html</trackback:ping><description><![CDATA[<p align="center">（cnBeta：<a title="http://www.cnbeta.com/articles/277936.htm" href="http://www.cnbeta.com/articles/277936.htm" target="_blank">http://www.cnbeta.com/articles/277936.htm</a>）</p> <p>首先贴个图，大家来一起念台词~</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/880134ac1d58_D1E/MSPYForever_2.png"><img title="MSPYForever" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="MSPYForever" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/880134ac1d58_D1E/MSPYForever_thumb.png" width="600" height="400"></a></p> <p>&nbsp;</p> <p>念完了木有？很激情澎湃义愤填膺有木有？</p> <p>&nbsp;</p> <p>这事情最早追溯到前年 8 月的一篇文章《<a href="http://www.cppblog.com/Streamlet/archive/2014/02/17/188249.html" target="_blank">十个步骤找回 Win8 中的微软拼音新体验模式</a>》，其实就是手工注册一个COM完事，只是傻逼大微软刻意弄了注册表权限来屏蔽，操作起来略微繁琐。到目前为止，Win8重装系统已经不下十次了，每次都是这样手工操作，我已经厌倦了。</p> <p>另外还有Win8.1上的问题，由于傻逼大微软已经完全删除了文件，就没法这么搞了，就算从Win8拷过文件来，也无法简单注册使用。加上我对8.1非常非常不感冒，一直没去研究。前些天看到之前的那篇文章里 Charles Leigh 回复了两篇文章（<a href="http://epigchina.wordpress.com/2013/11/06/mspy-in-windows-8-1/" target="_blank">ePig 那篇</a>是原创吧貌似，感谢），提供了解决方案。于是上个周末到现在就捣鼓个一键恢复工具，方便自己以后重装用，也方便广大微拼党。</p> <p>微拼党（包括我）孜孜不倦的追求微拼长句模式的情怀，让我非常感动。希望傻逼大微软看到我们的心声。别搞什么破词组输入法了，你搞不过本土这么多厂家的，你的下限也没有本土厂家低，唯一的优势可能就是没广告没弹窗了吧。至于输入算法什么的，在词组模式里面根本不足以体现得太多，长句模式才是考验啊。回头吧！</p> <p>下载页面：<a title="http://www.streamlet.org/Software/MSPYForever/" href="http://www.streamlet.org/Software/MSPYForever/" target="_blank">http://www.streamlet.org/Software/MSPYForever/</a></p> <p>CodePlex 项目页面：<a title="https://mspyforever.codeplex.com/" href="https://mspyforever.codeplex.com/" target="_blank">https://mspyforever.codeplex.com/</a></p> <p>&nbsp;</p> <p>请微拼党们多传播。有 Bug 及时反馈。</p><img src ="http://www.cppblog.com/Streamlet/aggbug/206335.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2014-03-26 01:10 <a href="http://www.cppblog.com/Streamlet/archive/2014/03/26/206335.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>将 Timer 对象化</title><link>http://www.cppblog.com/Streamlet/archive/2013/06/25/201279.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Mon, 24 Jun 2013 16:18:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2013/06/25/201279.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/201279.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2013/06/25/201279.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/201279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/201279.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Timer这玩意儿很常用，却又很烦人。烦人之处有四： 1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果将其设到HWND上，则 a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 必须手工维护Timer的ID，小心翼翼地保证这些ID不重复，可能有人（比如我）就不怎么喜欢手工维护硬编码的ID。 ...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2013/06/25/201279.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/201279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2013-06-25 00:18 <a href="http://www.cppblog.com/Streamlet/archive/2013/06/25/201279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>裸写一个进程外 COM 组件</title><link>http://www.cppblog.com/Streamlet/archive/2012/12/02/195900.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 02 Dec 2012 11:56:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/12/02/195900.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/195900.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/12/02/195900.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/195900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/195900.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 前面九月份的八篇关于COM的文章，说的都是进程内COM。那时，我们从一个含内嵌IE控件的窗口说起，根据COM协议手工书写了进程内COM组件，并由此积累了一些类似ATL的框架性代码。 &nbsp; 今天开始，我们把脚步迈向进程外组件。同样是从最基础的开始，本篇我们将根据进程外COM组件的加载规范手工编写一个EXE，然后用标准的COM调用方法来使用它。之前积累的框架性代码不属于第三方库，所以这里...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/12/02/195900.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/195900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-12-02 19:56 <a href="http://www.cppblog.com/Streamlet/archive/2012/12/02/195900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让 COM 脱离注册表</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/21/191436.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Thu, 20 Sep 2012 16:34:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/21/191436.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/191436.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/21/191436.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/191436.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/191436.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 在上一篇《在 DLL 中加入第二个 COM 类》的“单用户注册”一节中，我们曾提到脱离注册表依赖一事，现在我们来把这事儿给办了。 &nbsp; 注册 我们在之前支持了“regsvr32 /n /i:user COMProvider.dll”这一注册命令。这一注册命令给了我们一定的扩展余地。从ATL默认的代码来看，对于DllInstall，目前已定义的命令行参数似乎只有user，于是我们可以定...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/21/191436.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/191436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-21 00:34 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/21/191436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在 DLL 中加入第二个 COM 类</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/12/190331.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Tue, 11 Sep 2012 16:23:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/12/190331.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/190331.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/12/190331.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/190331.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/190331.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 在前面几篇文章里，我们已经成功脱离ATL写了一个COM组件，并且实现了自动化。今天，我们来加入第二个类，并且为加入第二个类做一些整理工作。 &nbsp; 为DLL建立一个Module类 在前面，我们为了使得DllCanUnloadNow能正确工作而放了一个全局变量LONG g_nModuleCount，并且在SampleClass的构造函数和析构函数里对它进行自增和自减。另外还有个IType...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/12/190331.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/190331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-12 00:23 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/12/190331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让COM组件可被跨语言调用</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/09/190026.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 09 Sep 2012 04:43:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/09/190026.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/190026.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/09/190026.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/190026.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/190026.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 错误修正 首先修正一下上篇（《裸写一个进程内 COM 组件》）中的例子的一个小问题。类厂的CreateInstance里面，上次是这么写的： &nbsp;     STDMETHODIMP ClassFactory::CreateInstance(_In_opt_ IUnknown *pUnkOuter, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/09/190026.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/190026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-09 12:43 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/09/190026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>裸写一个进程内 COM 组件</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/07/189762.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Thu, 06 Sep 2012 16:23:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/07/189762.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/189762.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/07/189762.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/189762.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/189762.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 前几天山寨了ATL的COM_INTERFACE，了解了一个COM类的如何进行通用的组织。今天再来学习下COM协议，看看如何实现一个COM组件——当然，也是不能用ATL的，不然就学不到什么了。 &nbsp; COM DLL说简单简单，说复杂也很复杂。说简单呢，其实貌似只要导出下面这五个函数就可以了： DllCanUnloadNow DllGetClassObject DllRegisterSe...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/07/189762.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/189762.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-07 00:23 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/07/189762.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写个含 Windows Media Player 的窗口</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/04/189470.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Tue, 04 Sep 2012 14:16:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/04/189470.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/189470.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/04/189470.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/189470.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/189470.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在上一篇中，我们实现了COM_INTERFACE宏，并且重新写了一个含有WebBrowser的窗口。在那里我们留了中间层OleContainer。为了验证OleContainer的可用性，现在来写一个含有Windows Media Player（下文简称“WMP”）控件的窗口。 &nbsp; WMP控件的容器类除了IOleClientSite、IOleInPlaceSite、IOleInPlace...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/04/189470.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/189470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-04 22:16 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/04/189470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>山寨一下 ATL 的 COM_INTERFACE</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/03/189321.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Mon, 03 Sep 2012 15:17:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/03/189321.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/189321.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/03/189321.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/189321.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/189321.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; 上一篇我们简单学习了下ATL 的继承链处理。可是，如果要裸写一个含内嵌IE控件的窗口，还是要写一个很长的QueryInterface，以及AddRef和Release，确保引用计数的正确性。于是我们不得不参考ATL的COM_TNTERFACE的处理技巧，来达到一定程度上的易用性。 &nbsp; 首先，除了IUnknown以外，其余所有涉及到的接口，均按上一篇的形式，弄成相应的IXXX...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/03/189321.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/189321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-03 23:17 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/03/189321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习下 ATL 的继承链处理</title><link>http://www.cppblog.com/Streamlet/archive/2012/09/02/189135.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 02 Sep 2012 05:56:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/09/02/189135.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/189135.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/09/02/189135.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/189135.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/189135.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我们先来看一组接口定义： &nbsp;     struct IX { &nbsp;&nbsp;&nbsp; virtual void MethodX() = 0; }; &nbsp; struct IXA : public IX { &nbsp;&nbsp;&nbsp; virtual void MethodXA() = 0; }; &nbsp; struct IXB : public IX {...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/09/02/189135.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/189135.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-09-02 13:56 <a href="http://www.cppblog.com/Streamlet/archive/2012/09/02/189135.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>初步性能测试</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/13/178704.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Wed, 13 Jun 2012 15:00:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/13/178704.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/178704.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/13/178704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/178704.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/178704.html</trackback:ping><description><![CDATA[<p>因为接下去要做优化工作，在此之前，先做下简单的性能测试。</p> <p>比较的对象是std::regex，暂时只比较两项：</p> <p>1、解析正则表达式的速度</p> <p>2、使用解析好的正则表达式去匹配字符串的速度。</p> <p>测试代码如下：<span lang="EN-US"><font face="Calibri"><font style="font-size: 10.5pt">&nbsp;</font></font></span></p> <table class="MsoTableGrid" style="border-top: medium none; border-right: medium none; border-collapse: collapse; border-bottom: medium none; border-left: medium none; mso-border-alt: solid windowtext .5pt; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt" cellspacing="0" cellpadding="0" border="1"> <tbody> <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"> <td style="border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; border-bottom: windowtext 1pt solid; padding-bottom: 0cm; padding-top: 0cm; padding-left: 5.4pt; border-left: windowtext 1pt solid; padding-right: 5.4pt; mso-border-alt: solid windowtext .5pt" valign="top" width="568"> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">PERFORMANCE_TEST_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff"><font style="font-size: 9.5pt">for</font></font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"> (</span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">int</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt"> i = 0; i &lt; 100000; ++i)</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">wregex r;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">r.assign(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://([a-zA-Z0-9\\-]+.)+[a-zA-Z]+/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">PERFORMANCE_TEST_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">();</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">PERFORMANCE_TEST_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff"><font style="font-size: 9.5pt">for</font></font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"> (</span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">int</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt"> i = 0; i &lt; 100000; ++i)</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">RegExp r;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">r.Parse(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://([a-zA-Z0-9\\-]+.)+[a-zA-Z]+/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">PERFORMANCE_TEST_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpParse100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">();</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">wregex r;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">r.assign(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://([a-zA-Z0-9\\-]+.)+[a-zA-Z]+/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a">PERFORMANCE_TEST_BEGIN</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">for</font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"> (</span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">int</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt"> i = 0; i &lt; 100000; ++i)</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">regex_match(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://w-1.w-2.w-3.streamlet.org/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">, r);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a">PERFORMANCE_TEST_END</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(StdRegExMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">();</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_BEGIN</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">RegExp r;</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">r.Parse(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://([a-zA-Z0-9\\-]+.)+[a-zA-Z]+/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a">PERFORMANCE_TEST_BEGIN</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">for</font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"> (</span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#0000ff">int</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt"> i = 0; i &lt; 100000; ++i)</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">{</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">r.Match(L</font></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://w-1.w-2.w-3.streamlet.org/"</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><span style="mso-spacerun: yes"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></span></span><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a">PERFORMANCE_TEST_END</font></span></font><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">(xlRegExpMatch100000);</font></span></font></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-autospace: ; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-justify: inter-ideograph" align="justify"><font face="Consolas"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#6f008a"><font style="font-size: 9.5pt">SECTION_END</font></font></span><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font style="font-size: 9.5pt">();</font></span></font><span lang="EN-US"></span></p></td></tr></tbody></table> <p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-justify: inter-ideograph" align="justify"><span lang="EN-US"><font face="Calibri"><font style="font-size: 10.5pt">&nbsp;</font></font></span></p> <p>前两则是分别使用std::wregex和xl::RegExp解析<font face="Consolas"><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000">"http://([a-zA-Z0-9\\-]+.)+[a-zA-Z]+/"</font></span></font></font>十万次，后两则是拿来匹配<font face="Consolas"><font style="font-size: 9.5pt"><span lang="EN-US" style="font-family: ; background-image: none; background-repeat: repeat; background-attachment: scroll; color: ; background-position: 0% 0%; mso-font-kerning: 0pt; mso-highlight: white"><font color="#800000"><a href="http://w-1.w-2.w-3.streamlet.org/">http://w-1.w-2.w-3.streamlet.org/</a></font></span></font></font>十万次。</p> <p>结果如下：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/0196573c0f97_12B8C/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/0196573c0f97_12B8C/image_thumb.png" width="271" height="255"></a></p> <p>匹配速度差很多，解析速度差不多。</p> <p>考虑到在解析“?”“+”“*”的时候，引入了很多ε边，于是对那部分做点优化，去除不必要的ε边和节点构造，然后再测试：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/0196573c0f97_12B8C/image_4.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/0196573c0f97_12B8C/image_thumb_1.png" width="267" height="250"></a></p> <p>可以看到有所提高，但是解析速度还是跟std:wregex的差很多，匹配速度有明显领先。目前只解析到ε边、-NFA，如果再做状态机转化，虽然会提高匹配速度，可是解析速度会进一步下降。因此，一开始就要考虑使用一种更高效的状态机存储方法。</p> <p>这两天着凉生病了，好难受啊……</p><img src ="http://www.cppblog.com/Streamlet/aggbug/178704.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-13 23:00 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/13/178704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析正则表达式（三）重复</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/08/178126.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Fri, 08 Jun 2012 15:35:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/08/178126.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/178126.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/08/178126.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/178126.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/178126.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 根据预告，这篇我们对“?”“+”“*”进行处理，实现对重复的支持。“x?”匹配0个或1个“x”，“x+”匹配1到任意个“x”，“x*”匹配0到任意个“x”。 &nbsp; 有了重复，就有贪婪模式和非贪婪模式。在贪婪模式下，“x+”匹配“xxxyyy”中的“xxx”；在非贪婪模式下，“x+”匹配“xxxyyy”中的第一个“x”。为了区别两种模式，按照通常的语法，我们在重复控制符号后面加一个“?...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/06/08/178126.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/178126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-08 23:35 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/08/178126.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析正则表达式（二）字符集合</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/04/177532.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Mon, 04 Jun 2012 14:19:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/04/177532.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/177532.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/04/177532.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/177532.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/177532.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 这篇我们要实现的是中括号表达式。 &nbsp; 一个中括号里写上任意数目的字符，表示匹配这些字符中的任何一个。比如“[abc]”匹配a或b或c。中括号里除了单个字符，也可以写字符区间，比如“[a-c]”就表示从a到c的所有字符，这里“a到c”是指内码连续的一系列字符，包含首尾的a和c。综合起来说，中括号里面可以放任意个字符或者字符区间，匹配所填字符或字符区间内的任意一个字符。比如“[acd-...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/06/04/177532.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/177532.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-04 22:19 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/04/177532.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析正则表达式（一）概要</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 03 Jun 2012 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/177330.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/177330.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/177330.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 想搞正则表达式解析器好久了。前面由于一些基础设施没准备好，没法开始动手。现在 xlLib 里头准备的差不多了，可以着手实施了。 &nbsp; 在做这件事之前，读了好几遍 @vczh 的文章《构造可配置词法分析器》《构造正则表达式引擎》（http://www.cppblog.com/vczh/archive/2008/05/22/50763.html），给了很大的帮助和启发，在这里表示感谢。（...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/177330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-03 15:16 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析正则表达式（一）概要</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 03 Jun 2012 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/177330.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/177330.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/177330.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 想搞正则表达式解析器好久了。前面由于一些基础设施没准备好，没法开始动手。现在 xlLib 里头准备的差不多了，可以着手实施了。 &nbsp; 在做这件事之前，读了好几遍 @vczh 的文章《构造可配置词法分析器》《构造正则表达式引擎》（http://www.cppblog.com/vczh/archive/2008/05/22/50763.html），给了很大的帮助和启发，在这里表示感谢。（...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/177330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-03 15:16 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解析正则表达式（一）概要</title><link>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 03 Jun 2012 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/177330.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/177330.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/177330.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言 想搞正则表达式解析器好久了。前面由于一些基础设施没准备好，没法开始动手。现在 xlLib 里头准备的差不多了，可以着手实施了。 &nbsp; 在做这件事之前，读了好几遍 @vczh 的文章《构造可配置词法分析器》《构造正则表达式引擎》（http://www.cppblog.com/vczh/archive/2008/05/22/50763.html），给了很大的帮助和启发，在这里表示感谢。（...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/177330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-06-03 15:16 <a href="http://www.cppblog.com/Streamlet/archive/2012/06/03/177330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用已有的 bind 构造 ScopeExit</title><link>http://www.cppblog.com/Streamlet/archive/2012/05/20/175510.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 20 May 2012 15:07:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/05/20/175510.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/175510.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/05/20/175510.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/175510.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/175510.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 对于 ScopeExit，以前有提到过（见《这种代码结构如何组织？goto or do…while(0)？》）。使用场景再简单提一下： bool GenFile() { &nbsp;&nbsp;&nbsp; HANDLE hFile = CreateFile(_T("Test.txt"), GENERIC_WRITE, 0, NUL, CREATE_ALWAYS, 0, NULL); &nbsp;...&nbsp;&nbsp;<a href='http://www.cppblog.com/Streamlet/archive/2012/05/20/175510.html'>阅读全文</a><img src ="http://www.cppblog.com/Streamlet/aggbug/175510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-05-20 23:07 <a href="http://www.cppblog.com/Streamlet/archive/2012/05/20/175510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调用约定总结</title><link>http://www.cppblog.com/Streamlet/archive/2012/05/12/174610.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Fri, 11 May 2012 17:36:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/05/12/174610.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/174610.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/05/12/174610.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/174610.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/174610.html</trackback:ping><description><![CDATA[<p>以前做 Function 的时候恰好取巧避免掉了，这些天在做 Bind，不得已要把每个调用约定罗列一遍。顺手把这些东西复习一下，总结如下——</p> <p>（所有内容针对 VC 编译平台）</p> <p>&nbsp;</p> <p>一、x86</p> <table cellspacing="0" cellpadding="2" width="855" border="0"> <tbody> <tr> <td valign="top" width="119">名称</td> <td valign="top" width="308">传参方式</td> <td valign="top" width="87">栈清理</td> <td valign="top" width="339">C 语言函数重命名（例：int func(int, double)）</td></tr> <tr> <td valign="top" width="122">__cdecl</td> <td valign="top" width="306">从右至左压栈</td> <td valign="top" width="89">主调函数</td> <td valign="top" width="338">前面加“_”（_func）</td></tr> <tr> <td valign="top" width="124">__stdcall</td> <td valign="top" width="304">从右至左压栈</td> <td valign="top" width="90">被调函数</td> <td valign="top" width="336">前面加“_”，后面加“@”再加参数十进制字节数（_func@12）</td></tr> <tr> <td valign="top" width="125">__fastcall</td> <td valign="top" width="303">前两个不大于DWORD长度的参数从左至右分别存到 ECX、EDX，其余从右至左压栈</td> <td valign="top" width="91">被调函数</td> <td valign="top" width="335">前面加“@”，后面加“@”再加参数十进制字节数（@func@12）</td></tr> <tr> <td valign="top" width="126">__thiscall</td> <td valign="top" width="302">ECX 存 this，其余从右至左压栈</td> <td valign="top" width="92">被调函数</td> <td valign="top" width="336">仅用于 C++</td></tr></tbody></table> <p>&nbsp;</p> <p>二、x64</p> <table cellspacing="0" cellpadding="2" width="855" border="0"> <tbody> <tr> <td valign="top" width="120">名称</td> <td valign="top" width="310">传参方式</td> <td valign="top" width="87">栈清理</td> <td valign="top" width="336">&nbsp;</td></tr> <tr> <td valign="top" width="123">__fastcall</td> <td valign="top" width="308">前四个整数/浮点数放在 RCX/XMM0、RDX/XMM1、R8/XMM2、R9/XMM3，其余压栈。<br>如果前 4 个参数分别为 int、float、long、double，它们将分别被存到 RCX、XMM1、R8、XMM3</td> <td valign="top" width="89">被调函数</td> <td valign="top" width="334">&nbsp;</td></tr></tbody></table> <p>64位编译环境下，可以指定 __cdecl、__stdcall、__fastcall，但是编译器会忽略它们。两个显示指定了不同调用约定的函数不构成重载，而构成重定义错误。</p><img src ="http://www.cppblog.com/Streamlet/aggbug/174610.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-05-12 01:36 <a href="http://www.cppblog.com/Streamlet/archive/2012/05/12/174610.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 的几种 cast 运算符到底是什么？与 C 风格的类型转换 (T)value 有什么区别和联系？</title><link>http://www.cppblog.com/Streamlet/archive/2012/03/23/168690.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Fri, 23 Mar 2012 01:53:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/03/23/168690.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/168690.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/03/23/168690.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/168690.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/168690.html</trackback:ping><description><![CDATA[<p>网上的文章但凡有提到 static_cast、const_cast、reinterpret_cast、dynamic_cast 的，都会语重心长的说，他们克服了 C 风格的类型转换的缺点，应当使用它们。</p> <p>可是，C 风格的到底有什么坏处？C++的这些 cast 又有什么好处呢？</p> <p>昨天以前，我连这些 cast 是什么都不知道（很惭愧）。昨天因为同事们提到这件事，于是小小研究了一下。一些实验代码如下：</p> <p>&nbsp;</p> <p>1、无继承的类型转换</p> <table style="border-collapse: collapse; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 0cm 0cm 0cm" class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0"> <tbody> <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"> <td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm" valign="top" width="590"> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">class</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> A</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">};</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">class</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> B</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">public</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt">:</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">operator</font></span> A()</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; {</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">return</font></span> A();</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; }</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">};</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">int</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> main()</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; B b;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a = (A)b;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">执行</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> operator A()</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a2 = <span style="color: "><font color="#0000ff">static_cast</font></span>&lt;A&gt;(b);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">执行</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> operator A()</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a3 = <span style="color: "><font color="#0000ff">dynamic_cast</font></span>&lt;A&gt;(b);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">不允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a4 = <span style="color: "><font color="#0000ff">reinterpret_cast</font></span>&lt;A&gt;(b);&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">不允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a5 = <span style="color: "><font color="#0000ff">const_cast</font></span>&lt;A&gt;(b);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">不允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">return</font></span> 0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p></td></tr></tbody></table> <p>&nbsp;</p> <p>2、const_cast</p> <table style="border-collapse: collapse; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 0cm 0cm 0cm" class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0"> <tbody> <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"> <td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm" valign="top" width="590"> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">struct</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> A</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> m;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A(<span style="color: "><font color="#0000ff">int</font></span> m = 0) : m(m)</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; {</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; }</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">};</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">int</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> main()</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">const</font></span> A a;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a2 = (A)a;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">允许，</font></span><span style="font-family: ; color: " lang="EN-US"><font face="Consolas">(A) </font></span><span style="font-family: ; color: "><font face="宋体">有没有都一样，</font></span><span style="font-family: ; color: " lang="EN-US"><font face="Consolas">a2 </font></span></font><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">是个新变量</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; a2.m = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// a2 </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">的改变不影响</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> a</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A &amp;a3 = (A &amp;)a;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; a3.m = 2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">影响</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> a</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; A &amp;a4 = a;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">不允许，</font></span><span style="font-family: ; color: " lang="EN-US"><font face="Consolas">const </font></span></font><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">限定起作用了</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A *pa5 = (A *)&amp;a;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; pa5-&gt;m = 3;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">影响</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> a</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; A *pa6 = &amp;a;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">不允许，</font></span><span style="font-family: ; color: " lang="EN-US"><font face="Consolas">const </font></span></font><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">限定起作用了</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; A aa2 = const_cast&lt;A&gt;(a);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A &amp;aa3 = <span style="color: "><font color="#0000ff">const_cast</font></span>&lt;A &amp;&gt;(a);&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; aa3.m = 2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">影响</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> a</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A *paa5 = <span style="color: "><font color="#0000ff">const_cast</font></span>&lt;A *&gt;(&amp;a);&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; paa5-&gt;m = 3;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><font color="#008000"><font style="font-size: 9.5pt"><span style="font-family: ; color: "><font face="宋体">影响</font></span></font><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt"> a</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">const</font></span> <span style="color: "><font color="#0000ff">int</font></span> i = 0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">const</font></span> <span style="color: "><font color="#0000ff">int</font></span> &amp;i2 = i;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">const</font></span> <span style="color: "><font color="#0000ff">int</font></span> *pi3 = &amp;i;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int j = const_cast&lt;int&gt;(i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> &amp;j2 = <span style="color: "><font color="#0000ff">const_cast</font></span>&lt;<span style="color: "><font color="#0000ff">int</font></span> &amp;&gt;(i2);&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> *pj3 = <span style="color: "><font color="#0000ff">const_cast</font></span>&lt;<span style="color: "><font color="#0000ff">int</font></span> *&gt;(pi3);&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">return</font></span> 0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span><span style="color: " lang="EN-US"></span></p></td></tr></tbody></table> <p>从第1点的试验，加上外界资料的说明，看上去const_case 只允许具有不同cv限定符的同类型之间的转换。 <p>值得注意的是，如果类型A不是指针或引用，不能使用const_cast（使用了也无意义，见 A a2 = (A)a 这一行） <p>在 const_cast 可以使用的情形，(T)value 形式都可以使用，(T)value 在功能上完全覆盖 const_cast。 <p>&nbsp;</p> <p>2、reinterpret_cast</p> <table style="border-collapse: collapse; mso-yfti-tbllook: 1184; mso-padding-alt: 0cm 0cm 0cm 0cm" class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0"> <tbody> <tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes"> <td style="border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; padding-bottom: 0cm; padding-left: 5.4pt; padding-right: 5.4pt; border-top: windowtext 1pt solid; border-right: windowtext 1pt solid; padding-top: 0cm" valign="top" width="590"> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">class</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> A</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">public</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt">:</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">operator</font></span> <span style="color: "><font color="#0000ff">int</font></span> *()</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; {</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">return</font></span> <span style="color: "><font color="#0000ff">nullptr</font></span>;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; }</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">};</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font face="Consolas"><span style="font-family: ; color: " lang="EN-US"><font color="#0000ff"><font style="font-size: 9.5pt">int</font></font></span><span style="font-family: " lang="EN-US"><font style="font-size: 9.5pt"> main()</font></span></font></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">{</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> i = 0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">double</font></span> d = 1.0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> *p = <span style="color: "><font color="#0000ff">nullptr</font></span>;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; </font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int di = reinterpret_cast&lt;int&gt;(d);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> pi = <span style="color: "><font color="#0000ff">reinterpret_cast</font></span>&lt;<span style="color: "><font color="#0000ff">int</font></span>&gt;(p);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int pi2 = static_cast&lt;int&gt;(p);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; double id = reinterpret_cast&lt;double&gt;(i);// </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; double pd = reinterpret_cast&lt;double&gt;(p);// </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> *ip = <span style="color: "><font color="#0000ff">reinterpret_cast</font></span>&lt;<span style="color: "><font color="#0000ff">int</font></span> *&gt;(i);&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int *ip2 = static_cast&lt;int *&gt;(i);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int *dp = reinterpret_cast&lt;int *&gt;(d);&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; A a;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> *pa = (<span style="color: "><font color="#0000ff">int</font></span> *)a;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">int</font></span> *pa2 = <span style="color: "><font color="#0000ff">static_cast</font></span>&lt;<span style="color: "><font color="#0000ff">int</font></span> *&gt;(a);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#008000">// </font></span></font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt" color="#008000">允许</font></font></span><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><font color="#008000"><span style="font-family: ; color: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">//&nbsp; int *p2 = reinterpret_cast&lt;int *&gt;(a);&nbsp;&nbsp; // </font></font></span><span style="font-family: ; color: "><font face="宋体"><font style="font-size: 9.5pt">不允许</font></font></span></font><span style="font-family: " lang="EN-US"></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">&nbsp;&nbsp;&nbsp; <span style="color: "><font color="#0000ff">return</font></span> 0;</font></font></span></p> <p style="margin: 0cm 0cm 0pt; text-autospace: " class="MsoNormal"><span style="font-family: " lang="EN-US"><font face="Consolas"><font style="font-size: 9.5pt">}</font></font></span></p></td></tr></tbody></table> <p>看上去，reinterpret_cast 可以理解为在指针和数值之间转换的一种方式，无关任何运算符重载，仅仅把指针转为字面值，或者把数字转为指针，转换的过程中值没有任何改变，只是告诉编译器不要报类型不匹配而已。 <p>另外，在reinterpret_cast可以使用的情形，static_cast 是不可以使用的，除非定义了相应的类型转换运算符。 <p>在 reinterpret_cast 可以使用的情形，(T)value 的方式同样可以完全胜任，(T)value 在功能上完全覆盖 reinterpret_cast。 <p>&nbsp; <p>dynamic_cast 我自认为还是理解的，就不试了。 <p>&nbsp; <p><b>综上，我的理解如下：</b><b></b> <p><b>1</b><b>、</b><b>static_cast + const_cast + reinterpret_cast = (T)value</b> <p><b>C++ </b><b>把原来</b><b>C</b><b>风格的的这三个</b><b>cast</b><b>拆分成了三个，三者相互正交。大多数情况下，应该是</b><b> static_cast </b><b>在取代着</b><b> (T)value</b><b>；只是在去除</b><b> cv </b><b>限定符的时候，换用</b><b> const_cast</b><b>；在取指针字面值的时候，换用</b><b> reinterpret_cast</b><b>。类型转换运算符 </b><b>operator T() </b><b>由 </b><b>static_cast </b><b>负责执行。</b><b></b> <p><b>2</b><b>、</b><b>dynamic_cast </b><b>是 </b><b>C++ </b><b>新增的，用于多态的情形，且只允许转换具有多态关系的继承树上的类型的指针和引用，不允许转换类型本身。它不是针对</b><b> (T)value</b><b>而出现的，两者没有任何竞争关系，只是取决于不同的需求。</b><b></b> <p><b></b> <p>（不知这样理解是否正确，请批评指正~） <p>至于网上推崇用新写法，是不是为了更细化而容易理解？有没有什么是 (T)value 做不到而 *_cast 能做到的？或者反过来？ <img src ="http://www.cppblog.com/Streamlet/aggbug/168690.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-03-23 09:53 <a href="http://www.cppblog.com/Streamlet/archive/2012/03/23/168690.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译一节 C++03 标准文档（3.10 左值和右值），请批评指正~</title><link>http://www.cppblog.com/Streamlet/archive/2012/02/29/166816.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Wed, 29 Feb 2012 14:50:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2012/02/29/166816.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/166816.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2012/02/29/166816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/166816.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/166816.html</trackback:ping><description><![CDATA[<p>3.10 Lvalues and rvalues [basic.lval]</p> <p><font color="#0000ff">左值和右值</font></p> <p>1 Every expression is either an lvalue or an rvalue.</p> <p><font color="#0000ff">表达式不是左值就是右值。</font></p> <p>2 An lvalue refers to an object or function. Some rvalue expressions—those of class or cv-qualified class type—also refer to objects. 47)</p> <p><font color="#0000ff">左值是指一个对象或者函数。某些右值（那些带或不带cv限定符的类类型）也是对象。</font></p> <p>3 [Note:<br>some built-in operators and function calls yield lvalues. [Example: if E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the function<br>int&amp; f();<br>yields an lvalue, so the call f() is an lvalue expression. ] ]</p> <p><font color="#0000ff">[注意：某些内置运算符以及一些函数调用会返回左值。[例1：如果 E 是一个指针类型的表达式，那么 *E 是一个左值表达式，指示指针 E 所指向的那个对象或者函数。例2：函数<br>int&amp; f();<br>返回左值，所以函数调用 f() 是一个左值表达式。] ]</font></p> <p>4 [Note: some built-in operators expect lvalue operands. [Example: built-in assignment operators all expect their left hand operands to be lvalues. ] Other built-in operators yield rvalues, and some expect them. [Example: the unary and binary + operators expect rvalue arguments and yield rvalue results. ] The discussion of each built-in operator in clause 5 indicates whether it expects lvalue operands and whether it yields an lvalue. ]</p> <p><font color="#0000ff">[注意：某些内置运算符需要左值操作数。[例：所有内置的赋值运算符的左操作数都必须是左值。] 有些内置运算符会返回右值结果，有些会需要右值操作数。[例：一元运算符“+”和二元运算符“+”都需要右值操作数，并且返回右值结果。] 我们在条款 5 中会对所有内置运算符进行讨论，指出它们的操作数和返回结果是左值还是右值。]</font></p> <p>5 The result of calling a function that does not return a reference is an rvalue. User defined operators are functions, and whether such operators expect or yield lvalues is determined by their parameter and return<br>types.</p> <p><font color="#0000ff">调用返回值为非引用类型的函数，结果是右值。用户自定义的运算符也是函数，这些运算符的操作数以及结果是左值还是右值，取决于（运算符重载）函数的参数和返回值类型。</font></p> <p>6 An expression which holds a temporary object resulting from a cast to a nonreference type is an rvalue (this includes the explicit creation of an object using functional notation (5.2.3)).</p> <p><font color="#0000ff">对非引用类型的转换表达式（包括使用函数式的记号进行显示创建）是右值，它将返回一个临时对象。</font></p> <p><br>__________________<br>47) Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues.</p> <p><font color="#0000ff">有些表达式，比如调用构造函数的表达式，以及调用返回类类型的函数的表达式，它们也是对象，且可以对它们调用成员函数，但这种表达式不是左值。</font></p> <p align="center"><font color="#008000">____________________________________华丽的分页符____________________________________</font></p> <p>&nbsp;</p> <p>7 Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue; see 4.1, 4.2, and 4.3.</p> <p><font color="#0000ff">如果在一个需要右值的场合出现了左值，这个左值将被转换成右值。<br>见 4.1、4.2、4.3。</font></p> <p>8 The discussion of reference initialization in 8.5.3 and of temporaries in 12.2 indicates the behavior of lvalues and rvalues in other significant contexts.</p> <p><font color="#0000ff">12.2 中关于引用的初始化和关于临时对象的讨论，也指出了左右值在其他重要场合的行为。</font></p> <p>9 Class rvalues can have cv-qualified types; non-class rvalues always have cv-unqualified types. Rvalues shall always have complete types or the void type; in addition to these types, lvalues can also have incomplete types.</p> <p><font color="#0000ff">类类型的右值可以具有 cv 限定符；非类类型的右值不能被 cv 限定符修饰。右值通常是完整类型或者 void 类型，而对于左值来说，除了完整类型和 void 类型外，还可以是不完整类型。</font></p> <p>10 An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]</p> <p><font color="#0000ff">通常情况下，如果要修改一个对象，它必须是左值。但在某些特定的场合，右值形式的类对象也可以被修改。[例：调用一个对象的成员函数（9.3），可以修改对象本身。]</font></p> <p>11 Functions cannot be modified, but pointers to functions can be modifiable.</p> <p><font color="#0000ff">函数（对象）不能（在运行时）被修改，但是函数指针可以。</font></p> <p>12 A pointer to an incomplete type can be modifiable. At some point in the program when the pointed to type is complete, the object at which the pointer points can also be modified.</p> <p><font color="#0000ff">指向一个不完整类型的指针可能是可修改的。当这个被指向的类型某时某刻成为完整类型后，这个指针所指向的那个对象也是可修改的。</font></p> <p>13 The referent of a const-qualified expression shall not be modified (through that expression), except that if it is of class type and has a mutable component, that component can be modified (7.1.5.1).</p> <p><font color="#0000ff">被 const 限定的表达式所对应的对象不能（通过该表达式）被修改；除非这个对象是类类型并且含有 mutable 成员，此时该 mutable 成员可以被修改。</font></p> <p>14 If an expression can be used to modify the object to which it refers, the expression is called modifiable. A program that attempts to modify an object through a nonmodifiable lvalue or rvalue expression is illformed.</p> <p><font color="#0000ff">如果一个表达式可以被用来修改此表达式对应的对象，那么这个表达式被称为可修改的。企图通过一个不可修改的左值者右值表达式去修改一个对象，是非法的。</font></p> <p>15 If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined 48):<br>— the dynamic type of the object,<br>— a cv-qualified version of the dynamic type of the object,<br>— a type that is the signed or unsigned type corresponding to the dynamic type of the object,<br>— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of<br>the object,<br>— an aggregate or union type that includes one of the aforementioned types among its members (including,<br>recursively, a member of a subaggregate or contained union),<br>— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,<br>— a char or unsigned char type.</p> <p><font color="#0000ff">如果程序通过下列类型之外类型的左值访问一个对象的值，其行为是未定义的：</font></p> <p><font color="#0000ff">——对象的动态类型；<br>——CV 限定的对象动态类型；<br>——对象的动态类型对应的有符号或无符号类型；<br>——CV 限定的对象动态类型有符号或无符号类型；<br>——一个成员中含有聚合或者联合类型的聚合或者联合类型（包括递归形式的定义以及成员中有子聚合类型或者包含一个联合）<br>——对象的动态类型的基类类型（可以被 cv 限定符修饰）<br>——char 或 unsigned char 类型</font></p> <p><br>__________________<br>48) The intent of this list is to specify those circumstances in which an object may or may not be aliased.<br><font color="#0000ff">给出这份列表的目的是指明一些特定情形，在这些情形下对象可能被重叠，但也有可能不是，我们无法预知。</font></p> <p align="center"><font color="#008000">____________________________________华丽的分隔符____________________________________</font></p> <p>&nbsp;</p> <p>以上，求指正，包括理解误区和语言组织不合理的，欢迎指出~ ^_^</p><img src ="http://www.cppblog.com/Streamlet/aggbug/166816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2012-02-29 22:50 <a href="http://www.cppblog.com/Streamlet/archive/2012/02/29/166816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如果要拟定一份代码规范，哪些内容应该列入？</title><link>http://www.cppblog.com/Streamlet/archive/2011/07/12/150791.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Tue, 12 Jul 2011 14:22:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/07/12/150791.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/150791.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/07/12/150791.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/150791.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/150791.html</trackback:ping><description><![CDATA[<p>如题，大致看了下网上能找到的一些规范，觉得大体有这么三个方面吧，一个是排版方面的，一个是命名方面的，一个是书写逻辑方面的。</p> <p>排版方面的大概有，如何缩进，如何使用空格、换行，等等。命名方面的包括变量、函数、类、文件的取名等等。书写逻辑方面的就比较多了，可能包括：<br>是否全面使用异常、出错处理资源清理如何组织、如何利用编译提示防止常见错误……</p> <p>一时间列不全。网上常见的文档我会参考的。除此之外，想从大家这里征求下，以上几个大方面之外，还有没有比较重要的方面？大家日常工作中有没有遇到一些特别希望别人也使用和自己一样的方式做的事？以及，哪些规定比较容易被推动？哪些规定不容易被推动？如果有一个规则强加在你头上，你会有怎样的心理？等等……</p> <p>如果您有想法，请回复下，我们讨论讨论^_^</p> <p>----------</p> <p>顺便再问个问题，Windows 上的开发，大家喜欢动态链接 CRT（/MD、/MDd） 还是静态链接 CRT（/MT、/MTd）？为什么？个人倾向于哪种？在公司里又是怎样做的？</p><img src ="http://www.cppblog.com/Streamlet/aggbug/150791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-07-12 22:22 <a href="http://www.cppblog.com/Streamlet/archive/2011/07/12/150791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何写 执行耗时任务的、可随时立即退出的函数 呢？</title><link>http://www.cppblog.com/Streamlet/archive/2011/05/26/147133.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Wed, 25 May 2011 16:36:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/05/26/147133.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/147133.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/05/26/147133.html#Feedback</comments><slash:comments>29</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/147133.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/147133.html</trackback:ping><description><![CDATA[<p>如题。</p> <p>稍微解释下，因为有可能有人会误会：放新线程里面去不就可以了？这没有解决问题。如此的话，你那个线程函数怎么写？或者线程函数里调用的某个任务函数怎么写？总之，多线程虽然总是出现在这些问题的解决方案中，但不是多线程解决了这个问题。嗯……不知道说清楚了没？</p> <p>目前我心里的答案只有这一种模式：</p> <p>bool DoTask(HANDLE hQuitSignal)<br>{<br>&nbsp;&nbsp;&nbsp; while (!QuitCondition)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (WaitForSingleObject(hQuitSignal, 0) == WAIT_OBJECT_0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Do something<br>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; return true;<br>}<br></p> <p>其中，“// Do something”部分要细化到瞬间执行完成的细度。</p> <p>但是我很困惑的是，如果这些任务很繁重，难道我必须每进行一些操作就 if (WaitForSingleObject(hQuitSignal, 0) == WAIT_OBJECT_0) 检查下吗？这样岂不是这种检测代码充斥在任务中了？</p> <p>不知各位有何经验和体会，求教~</p><img src ="http://www.cppblog.com/Streamlet/aggbug/147133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-05-26 00:36 <a href="http://www.cppblog.com/Streamlet/archive/2011/05/26/147133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个简单的 Tuple 实现</title><link>http://www.cppblog.com/Streamlet/archive/2011/04/28/145249.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Thu, 28 Apr 2011 14:05:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/04/28/145249.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/145249.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/04/28/145249.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/145249.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/145249.html</trackback:ping><description><![CDATA[<p>标题中说的 Tuple 是指类似 boost::tuple 这样的设施。</p> <p>很多时候我们需要返回/传入一堆参数，所以不得不每次定义一些为了数据传输的结构。Tuple 就是用来解决这一问题的，它提供即时构造一个这样的结构体的功能。而所付出的代价是，丧失各个成员的明确含义，只留下成员的序号。</p> <p>两个元素的 Tuple 就是 Pair，如 std::pair。下面我们来建立针对有限个元素的 Tuple。对于一个元素、两个元素、三个元素，我们可以分别如下实现：</p> <p><font face="Consolas">template &lt;typename T0&gt;<br>struct Tuple<br>{<br>&nbsp;&nbsp;&nbsp; T0 _0;<br>};</font></p> <p><font face="Consolas">template &lt;typename T0, typename T1&gt;<br>struct Tuple<br>{<br>&nbsp;&nbsp;&nbsp; T0 _1;<br>&nbsp;&nbsp;&nbsp; T1 _1;<br>};</font></p> <p><font face="Consolas">template &lt;typename T0, typename T1, typename T2&gt;<br>struct Tuple<br>{<br>&nbsp;&nbsp;&nbsp; T0 _1;<br>&nbsp;&nbsp;&nbsp; T1 _1;<br>&nbsp;&nbsp;&nbsp; T2 _2;<br>};</font></p> <p>但是这三个写在一起，就会出错。为此，我们可以先定义一个含足够多模版参数的 Tuple，然后上面三个分别作为偏特化版本：</p> <p><font face="Consolas">template &lt;typename T0 = NullType, typename T1= NullType, typename T2= NullType, typename T3= NullType, typename T4= NullType&gt;<br>struct Tuple;</font></p> <p><font face="Consolas">template &lt;typename T0&gt;<br>struct Tuple&lt;T0&gt;<br>{<br>&nbsp;&nbsp;&nbsp; T0 _0;<br>};</font></p> <p><font face="Consolas">template &lt;typename T0, typename T1&gt;<br>struct Tuple&lt;T0, T1&gt;<br>{<br>&nbsp;&nbsp;&nbsp; T0 _1;<br>&nbsp;&nbsp;&nbsp; T1 _1;<br>};</font></p> <p><font face="Consolas">template &lt;typename T0, typename T1, typename T2&gt;<br>struct Tuple&lt;T0, T1, T2&gt;<br>{<br>&nbsp;&nbsp;&nbsp; T0 _1;<br>&nbsp;&nbsp;&nbsp; T1 _1;<br>&nbsp;&nbsp;&nbsp; T2 _2;<br>};</font></p> <p>如果手写的话，这也可以。如果不手写，我们可以继续用之前《<a href="http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html" target="_blank">C++ 下 Function 对象的实现（下）</a>》中的宏循环方案。此方案的一个正式版本见 <a title="xlMacros.h" href="http://xllib.codeplex.com/SourceControl/changeset/view/7851#124600" target="_blank">xlMacros.h</a>。</p> <p>定义带默认值 NullType 的模版参数声明序列如下：</p> <p><font face="Consolas">#define XL_TUPLE_TYPENAME_DECLARE_NT_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp; typename T##n = NullType<br>#define XL_TUPLE_TYPENAME_DECLARE_NT(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_TYPENAME_DECLARE_NT_PATTERN, n, XL_COMMA)</font><br></p> <p>它将被展开为： <font face="Consolas">typename T0 = NullType, typename T1 = NullType, typename T2 = NullType, …, typename Tn = NullType</font></p> <p>定义不带默认值的模版参数声明序列如下：</p> <p><font face="Consolas">#define XL_TUPLE_TYPENAME_DECLARE_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typename T##n<br>#define XL_TUPLE_TYPENAME_DECLARE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_TYPENAME_DECLARE_PATTERN, n, XL_COMMA)</font><br></p> <p>它将被展开为：<font face="Consolas">typename T0, typename T1, typename T2, …, typename Tn</font></p> <p>定义模版参数使用序列如下：</p> <p><font face="Consolas">#define XL_TUPLE_TYPENAME_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T##n<br>#define XL_TUPLE_TYPENAME_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_TYPENAME_LIST_PATTERN, n, XL_COMMA)<br></font></p> <p>它将被展开为 <font face="Consolas">T0, T1, T2, …, Tn</font></p> <p>定义成员变量声明序列如下：</p> <p><font face="Consolas">#define XL_TUPLE_MEMBER_DECLARE_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T##n _##n;<br>#define XL_TUPLE_MEMBER_DECLARE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_MEMBER_DECLARE_PATTERN, n, XL_NIL)<br></font></p> <p>它将被展开为：<font face="Consolas">T0 _0; T1 _1; T2 _2; … Tn _n;</font></p> <p>现在我们开始组装：</p> <p><font face="Consolas">#ifndef XL_TUPLE_DEFINE_MAX<br>#define XL_TUPLE_DEFINE_MAX&nbsp; 20<br>#endif<br></font></p> <p><font face="Consolas">template &lt;XL_TUPLE_TYPENAME_DECLARE_NT(XL_INC(XL_TUPLE_DEFINE_MAX))&gt;<br>struct Tuple;</font></p> <p><font face="Consolas">template &lt;XL_TUPLE_TYPENAME_DECLARE(n)&gt;<br>struct Tuple&lt;XL_TUPLE_TYPENAME_LIST(n)&gt;<br>{<br>&nbsp;&nbsp;&nbsp; XL_TUPLE_MEMBER_DECLARE(n)<br>};</font><br></p> <p>其中后一个还带有宏参数 n。我们将这整一个定义成宏，然后进行宏循环：</p> <p><font face="Consolas">#define XL_TUPLE_IMPLEMENT_PATTERN(n)&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>template &lt;XL_TUPLE_TYPENAME_DECLARE(n)&gt; \<br>struct Tuple&lt;XL_TUPLE_TYPENAME_LIST(n)&gt; \<br>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp; XL_TUPLE_MEMBER_DECLARE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \</font></p> <p><font face="Consolas">#define XL_TUPLE_IMPLEMENT(n)&nbsp;&nbsp;&nbsp; XL_REPY(XL_TUPLE_IMPLEMENT_PATTERN, n, XL_NIL)<br></font></p> <p>之后再使用这个宏：</p> <p><font face="Consolas">XL_TUPLE_IMPLEMENT(XL_TUPLE_DEFINE_MAX)</font></p> <p>到此为止，上文一开始提出的 Tuple 已经实现，并支持到最大约 20 个元素左右。</p> <p>然后我们可以考虑增加各种方便使用的功能。</p> <ol> <li>默认构造函数。<br></li> <li>带有 n 个参数的构造函数。相关宏定义：<br><font face="Consolas">#define XL_TUPLE_INITIALIZE_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _##n(_##n)<br>#define XL_TUPLE_INITIALIZE_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_INITIALIZE_LIST_PATTERN, n, XL_COMMA)<br></font></li> <li>拷贝构造函数。相关宏定义：<br><font face="Consolas">#define XL_TUPLE_INITIALIZE_LIST_COPY_PATTERN(n)&nbsp;&nbsp;&nbsp; _##n(that._##n)<br>#define XL_TUPLE_INITIALIZE_LIST_COPY(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_INITIALIZE_LIST_COPY_PATTERN, n, XL_COMMA)<br></font></li> <li><font face="Consolas">赋值函数：<br>#define XL_TUPLE_ASSIGN_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;_##n = that._##n;<br>#define XL_TUPLE_ASSIGN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_ASSIGN_PATTERN, n, XL_NIL)<br></font></li> <li><font face="Consolas">各种比较函数。请注意对各元素的相应比较运算符的依赖。这里定义成，Tuple 的 &lt; 只依赖于各元素的 &lt;，Tuple 的 != 也只依赖于各元素的 !=，如此类推。<br></font><font face="Consolas"><br>#define XL_TUPLE_EQUAL_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;_##n == that._##n<br>#define XL_TUPLE_EQUAL(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_EQUAL_PATTERN, n, &amp;&amp;)</font></li> <p><font face="Consolas">#define XL_TUPLE_NOT_EQUAL_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;_##n != that._##n<br>#define XL_TUPLE_NOT_EQUAL(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_NOT_EQUAL_PATTERN, n, ||)</font></p> <p><font face="Consolas">#define XL_TUPLE_LITTER_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this-&gt;_##n &lt; that._##n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (that._##n &lt; this-&gt;_##n)&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>#define XL_TUPLE_LITTER(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_LITTER_PATTERN, n, XL_NIL)</font></p> <p><font face="Consolas">#define XL_TUPLE_GREATER_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (this-&gt;_##n &gt; that._##n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (that._##n &gt; this-&gt;_##n)&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>#define XL_TUPLE_GREATER(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XL_REPZ(XL_TUPLE_GREATER_PATTERN, n, XL_NIL)<br></font><br></p></ol> <p>同时 Tuple 中也增加相应的函数，即可。</p> <p>最终代码见 <a title="xlTuple.h" href="http://xllib.codeplex.com/SourceControl/changeset/view/7851#141911" target="_blank">xlTuple.h</a>，这里不贴了。</p> <p>请多多指正。</p><img src ="http://www.cppblog.com/Streamlet/aggbug/145249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-04-28 22:05 <a href="http://www.cppblog.com/Streamlet/archive/2011/04/28/145249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何实现一个支持不同类型的 max/min 函数？</title><link>http://www.cppblog.com/Streamlet/archive/2011/03/29/142974.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Tue, 29 Mar 2011 13:27:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/03/29/142974.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/142974.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/03/29/142974.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/142974.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/142974.html</trackback:ping><description><![CDATA[<p>有个需求，能否做到实现一个类似这样的函数：</p> <p><font face="Consolas">template &lt;typename T1, typename T2&gt;<br>XXX Min(T1 t1, T2 t2)<br>{<br>&nbsp;&nbsp;&nbsp; return (t1 &lt; t2 ? t1 : t2);<br>}</font>  <p>其中 XXX 是我们要推导出的类型。  <p>以下是一个失败的尝试。  <p>我记得 Loki 里有关于如何判断某个类型能否隐式转换为另一个类型的东西，大意如下：  <p><font face="con">template &lt;typename T, typename U&gt;<br>class Conversion<br>{<br>private:<br>&nbsp;&nbsp;&nbsp; typedef char Small;<br>&nbsp;&nbsp;&nbsp; class Big { char XXX[2]; };<br>&nbsp;&nbsp;&nbsp; static Small Test(U);<br>&nbsp;&nbsp;&nbsp; static Big Test(...);<br>&nbsp;&nbsp;&nbsp; static T MakeT();<br>public:<br>&nbsp;&nbsp;&nbsp; enum<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Exists = (sizeof(Test(MakeT())) == sizeof(Small)),<br>&nbsp;&nbsp;&nbsp; };<br>};</font>  <p>如此，Conversion&lt;T, U&gt;::Exists 就能判断 T 到 U 的转换是否存在了。  <p>然后再搞个选择：  <p><font face="Consolas">template &lt;bool Condition, typename TypeIfTrue, typename TypeIfFalse&gt;<br>struct Select<br>{<br>&nbsp;&nbsp;&nbsp; typedef TypeIfFalse Type;<br>}; </font> <p><font face="Consolas">template &lt;typename TypeIfTrue, typename TypeIfFalse&gt;<br>struct Select&lt;true, TypeIfTrue, TypeIfFalse&gt;<br>{<br>&nbsp;&nbsp;&nbsp; typedef TypeIfTrue Type;<br>};</font>  <p>最后，再来个：  <p>struct NullType;  <p>template &lt;typename T, typename U&gt;<br>struct CommonType<br>{<br>&nbsp;&nbsp;&nbsp; typedef typename Select&lt;Conversion&lt;T, U&gt;::exists, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typename Select&lt;Conversion&lt;U, T&gt;::exists,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NullType&gt;::Type<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;::Type Type;<br>};  <p>那么 CommonType&lt;T1, T2&gt; 就是 T1 和 T2 之间哪个是他们的共有类型了。  <p>测试：  <p>int main()<br>{<br>&nbsp;&nbsp;&nbsp; CommonType&lt;int, double&gt;::Type m = 0;  <p>&nbsp;&nbsp;&nbsp; return 0;<br>}  <p>调试，确认 m 是 double 的。但是反过来写 CommonType&lt;double, int&gt;::Type m = 0;，m 却是 int 的。  <p>这说明这套机制一开始就有问题，Test(U) 和 Test(…) 两个重载函数中，Test(…) 不会在需要 double 转 int 时胜出。这是第一个问题。  <p>第二个问题，当写下如下代码的时候：  <p>template &lt;typename T1, typename T2&gt;<br>CommonType&lt;T1, T2&gt;::Type Min(T1 t1, T2 t2)<br>{<br>&nbsp;&nbsp;&nbsp; return (t1 &lt; t2 ? t1 : t2);<br>}  <p>编译无法通过。<u>原因是返回类型中的 CommonType 中的模板参数 T、U 无法接受此时还不能确定的 T1、T2。</u></p> <p><font color="#ff0000">(更正：不是这个原因，返回类型前加 typename 即可。现在问题还是第一个问题。)</font></p> <p>请教各位，有没有什么方法做到？欢迎指教~</p> <p>C++ 0x 中就能很方便做到了：</p> <p>template &lt;typename T1, typename T2&gt;<br>auto Min(T1 t1, T2 t2) -&gt; decltype(t1 + t2)<br>{<br>&nbsp;&nbsp;&nbsp; return (t1 &lt; t2 ? t1 : t2);<br>}  <p>int main()<br>{<br>&nbsp;&nbsp;&nbsp; int a = 2;<br>&nbsp;&nbsp;&nbsp; double b = 1.0;<br>&nbsp;&nbsp;&nbsp; auto m = Min(a, b);  <p>&nbsp;&nbsp;&nbsp; return 0;<br>}</p><img src ="http://www.cppblog.com/Streamlet/aggbug/142974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-03-29 21:27 <a href="http://www.cppblog.com/Streamlet/archive/2011/03/29/142974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>觉得 Loki::ScopeGuard 似乎不该在它自己里面 try &amp;hellip; catch &amp;hellip;</title><link>http://www.cppblog.com/Streamlet/archive/2011/03/23/142543.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Wed, 23 Mar 2011 01:39:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/03/23/142543.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/142543.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/03/23/142543.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/142543.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/142543.html</trackback:ping><description><![CDATA[<p>ScopeGuard 只是帮我们调用一个函数而已，至于这个函数是否有异常出来，它不该悄悄地把它吞了，而应该还我们本来面目，不知道是不是？可是为什么几乎所有介绍 ScopeGuard 的文章都说这 try … catch … 用得好呢？</p><img src ="http://www.cppblog.com/Streamlet/aggbug/142543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-03-23 09:39 <a href="http://www.cppblog.com/Streamlet/archive/2011/03/23/142543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个好玩的玩意儿：VS 的 autoexp.txt</title><link>http://www.cppblog.com/Streamlet/archive/2011/02/27/140742.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 27 Feb 2011 09:10:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/02/27/140742.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/140742.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/02/27/140742.html#Feedback</comments><slash:comments>22</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/140742.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/140742.html</trackback:ping><description><![CDATA[<p>嗯，写篇文章的目的是为了把我最新（现在是次新）的那篇文章给刷下去——我不想每次看见它了。</p> <p>不知大家有没有发现，当使用 VS 来调试代码的时候，那些 STL 容器的信息会以比较看得懂的方式显示出来：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_thumb.png" width="862" height="514"></a></p> <p>&nbsp;</p> <p>而我们自己写的，它只能按照数据成员来显示，如果数据结构稍微复杂点，看这些直接显示的内容得到的有用信息就会很少了：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_thumb_1.png" width="746" height="293"></a></p> <p>&nbsp;</p> <p>那么，是否有办法能让 IDE 按照我们设想的方式来显示数据呢？答案是肯定的。这个配置就位于 autoexp.txt 中（具体路径为 X:\Program Files\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\autoexp.dat，如果是 VS 不同版本，“Microsoft Visual Studio 10.0”中的版本号换成其他的即可，VS 2005 以上版本都支持）。</p> <p>在里面搜索 vector，可以找到作用于 vector 的调试信息显示方式的语句：</p> <table style="color: #4b4b4b" border="0" cellspacing="0" cellpadding="2" width="499"> <tbody> <tr> <td valign="top" width="497"> <p>std::vector&lt;*&gt;{<br>&nbsp;&nbsp;&nbsp; preview (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "[",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $e._Mylast - $e._Myfirst,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "](",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #array(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr: $e._Myfirst[$i],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size: $e._Mylast - $e._Myfirst<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ")"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; )</p> <p>&nbsp;&nbsp;&nbsp; children (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #([size] : $e._Mylast - $e._Myfirst),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #([capacity] : $e._Myend - $e._Myfirst),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #array(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr: $e._Myfirst[$i],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size: $e._Mylast - $e._Myfirst<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; )<br>}</p></td></tr></tbody></table> <p>这个语法的详细官方说明好像没有，不过大体上可以猜出来。</p> <p>第一行 std::vector&lt;*&gt; 是类型，说明下面的内容针对 std::vector，并且适用于任意模版参数。紧接着是一个大括号括起来的段落。</p> <p>preview 开始的那一段表示当该变量单行显示的时候该如何显示，也就是下图第二列的样子：<br><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_8.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_thumb_3.png" width="460" height="35"></a></p> <p>IDE 会依次显示 preview(#( … )) 括号内的以逗号分隔的内容，加引号的会原样显示，变量用 $e 引用（将 $e 视为该类型的一个变量）。</p> <p>除了直接引号，变量的运算结果外，这里还可以写一些高级点的玩意儿，如 #array，#list，#tree。</p> <p>#array 的格式为：<br>#array(<br>&nbsp;&nbsp;&nbsp; expr: … ,<br>&nbsp;&nbsp;&nbsp; size:&nbsp; …<br>)<br>其中 expr 里可以使用 $i，$i 为元素 index，size 表示元素个数。最终的结果为：<br>$i=0时的expr, $i=1时的expr, …, $i=size时的expr。</p> <p>假设有一个结构：<br>struct Vector<br>{<br>&nbsp;&nbsp;&nbsp; int *pData;<br>&nbsp;&nbsp;&nbsp; int nCount;<br>};<br>其中 p 是指向一块 count 个 int 的内存。如果要依次显示这 count 个数字，preview 中应该写：<br>preview (<br>&nbsp;&nbsp;&nbsp; #(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #array(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr: $e.pData[$i],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size: $e.nCount<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>&nbsp;&nbsp;&nbsp; )<br>)</p> <p>#list 的格式为：<br>#list(<br>&nbsp;&nbsp;&nbsp; head: … ,<br>&nbsp;&nbsp;&nbsp; size: … ,<br>&nbsp;&nbsp;&nbsp; next: …<br>) : …<br>其中 head 是指向第一个 Node 的指针，size 表示元素个数，next 表示 Node 中指向下一个 Node 的分量名，最后冒号后面还要写一个 Node 中的值分量，也就是要显示的那个变量。</p> <p>假设有结构：<br>struct ListNode<br>{<br>&nbsp;&nbsp;&nbsp; int nData;<br>&nbsp;&nbsp;&nbsp; ListNode *pNext;<br>};<br>struct List<br>{<br>&nbsp;&nbsp;&nbsp; ListNode *pHead；<br>&nbsp;&nbsp;&nbsp; int nCount;<br>};<br>preview 的写法为：<br>preview (<br>&nbsp;&nbsp;&nbsp; #(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #list(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head: $e.pHead,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size: $e.nCount,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; next: pNext<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) : $e.nData&nbsp;&nbsp;&nbsp; // 注意，这里的 $e 代表 ListNode，上面两个 $e 都代表 List<br>&nbsp;&nbsp;&nbsp; )<br>)</p> <p>#tree的格式为<br>#tree(<br>&nbsp;&nbsp;&nbsp; head: …,<br>&nbsp;&nbsp;&nbsp; left: …,<br>&nbsp;&nbsp;&nbsp; right: …,<br>&nbsp;&nbsp;&nbsp; size: …<br>) : …<br>其中 head 是指向根节点的指针，left 和 right 分别是指向左右子树的分量名，size 表示元素个数，最后冒号后面写节点中的值分量。IDE会对整棵树做中序遍历。</p> <p>假设有结构：<br>struct TreeNode<br>{<br>&nbsp;&nbsp;&nbsp; int nData;<br>&nbsp;&nbsp;&nbsp; TreeNode *pLeft;<br>&nbsp;&nbsp;&nbsp; TreeNode *pRight;<br>};<br>struct Tree<br>{<br>&nbsp;&nbsp;&nbsp; TreeNode *pRoot;<br>&nbsp;&nbsp;&nbsp; int nCount;<br>};<br>preview 的写法为：<br>preview (<br>&nbsp;&nbsp;&nbsp; #(<br>&nbsp;&nbsp;&nbsp; #tree(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head: $e.pRoot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left: pLeft,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right: Right,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size: $e.nCount<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ) : $e.nData // 注意，这里的 $e 代表 TreeNode，上面两个 $e 都代表 Tree<br>&nbsp;&nbsp;&nbsp; )<br>)</p> <p><br>preview 的格式就到此。接下来是 children，它用于描述点击变量左边的加号后，展开的内容怎么显示，如图：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_10.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_thumb_4.png" width="199" height="119"></a></p> <p>IDE 会依次显示 children(#( … )) 括号内的以逗号分隔的内容，每个显示为一行。刚才的 #array, #list, #tree 都可以用，会显示成第一列索引第二列值的样子。<br>另外可以用 #(first, second) 的格式，first 会原样显示在第一列，second 会求值显示在第二列。</p> <p>&nbsp;</p> <p>了解以上这些内容，我们已经可以针对 STL 的那些数据结构做自定义显示了，对一些别的数据结构作简单的自定义显示也不难。</p> <p>&nbsp;</p> <p>最后给个效果图，定义了我自己的那些容器的显示方式。怎么样，看上去一定比开头给出的那个冷冰冰的样子好很多吧？</p> <p><a href="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/Streamlet/Windows-Live-Writer/f42585ce8478_E196/image_thumb_2.png" width="751" height="503"></a></p><img src ="http://www.cppblog.com/Streamlet/aggbug/140742.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-02-27 17:10 <a href="http://www.cppblog.com/Streamlet/archive/2011/02/27/140742.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 下 Function 对象的实现（下）</title><link>http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Mon, 17 Jan 2011 13:59:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/138693.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/138693.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/138693.html</trackback:ping><description><![CDATA[<p>目录：</p> <p><a href="http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html" target="_blank">C++ 下 Function 对象的实现（上）</a><br><a href="http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html" target="_blank">C++ 下 Function 对象的实现（下）</a></p> <p>上篇中，我们实现了一个支持 R () 型函数的 Function。补充说明一下，在我们对成员函数的支持中，我们是这样定义的：</p> <p><font face="Consolas">template &lt;typename R, typename T&gt;<br>class MemberFunction0 : public FunctionBase0&lt;R&gt;<br>{</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; R (T::*m_pMemFun)();<br>&nbsp;&nbsp;&nbsp; T *m_pObj;<br>};<br></font></p> <p>Loki 特意在著作中提醒我们，这里的 T 最好不要是函数类型，改为函数指针类型，如此该类的支持范围将扩大。如下：</p> <p><font face="Consolas">template &lt;typename R, typename P, typename T&gt;<br>class MemberFunction0 : public FunctionBase0&lt;R&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (m_pObj-&gt;*m_pMemFun)();<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; MemberFunction0(P pObj, R (T::*pMemFun)())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pObj(pObj), m_pMemFun(pMemFun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; R (T::*m_pMemFun)();<br>&nbsp;&nbsp;&nbsp; P m_pObj;<br>};</font></p> <p>于是，P 和 T 的关系不那么紧密了，P 不一定非要 T* 不可，也可以是诸如 SmartPtr&lt;T&gt; 之类的玩意儿。原本只支持传入一个对象和该对象的成员函数的，现在变成传入一个具有指针概念的东东和一个成员函数，只要这个“指针”使用运算符 –&gt; 去调用那个成员函数合乎语法即可。</p> <p>接下来，我们来扩展这个 Function，以支持拥有数目在给定上限内的任意参数的函数。</p> <p>我们先来手工写一下，看看如何支持带一个参数的函数。首先定义一个虚基类：</p> <p><font face="Consolas">template &lt;typename R, typename T0&gt;<br>class FunctionBase1<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual R Invoke(T0) = 0;<br>&nbsp;&nbsp;&nbsp; virtual ~FunctionBase1() {}<br>};</font></p> <p>实现两个版本，分别支持非成员函数和成员函数：</p> <p><font face="Consolas">template &lt;typename R, typename T0, typename T&gt;<br>class Function1 : public FunctionBase1&lt;R, T0&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke(T0 v0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_Fun(v0);<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; Function1(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_Fun(fun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; T m_Fun;<br>};</font></p> <p><font face="Consolas">template &lt;typename R, typename P, typename T, typename T0&gt;<br>class MemberFunction1 : public FunctionBase1&lt;R, T0&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke(T0 v0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (m_pObj-&gt;*m_pMemFun)(v0);<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; MemberFunction1(P pObj, R (T::*pMemFun)(T0))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pObj(pObj), m_pMemFun(pMemFun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; R (T::*m_pMemFun)(T0);<br>&nbsp;&nbsp;&nbsp; P m_pObj;<br>};</font></p> <p>增加一个函数引用萃取的偏特化版本：</p> <p>template &lt;typename RetType, typename T0&gt;<br>struct FunctionTraits&lt;RetType (T0)&gt;<br>{<br>&nbsp;&nbsp;&nbsp; typedef RetType (&amp;ParamType)(T0);<br>};<br></p> <p>增加一个 Function 类的偏特化版本：</p> <p><font face="Consolas">template &lt;typename R, typename T0&gt;<br>class Function&lt;R (T0)&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new Function1&lt;R, T0, typename FunctionTraits&lt;T&gt;::ParamType&gt;(fun))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; template &lt;typename P, typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(P pObj, R (T::*pMemFun)(T0))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new MemberFunction1&lt;R, P, T, T0&gt;(pObj, pMemFun))<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; ~Function()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete m_pFunBase;<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; R operator ()(T0 v0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_pFunBase-&gt;Invoke(v0);<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; FunctionBase1&lt;R, T0&gt; *m_pFunBase;<br>};</font></p> <p>现在，我们可以跑一下测试代码了：</p> <p><font face="Consolas">Function&lt;int (int)&gt; f1(&amp;intfun1);<br>Function&lt;int (int)&gt; f1_(intfun1);<br>Function&lt;int (int)&gt; f2(intfunctor1);<br>Function&lt;int (int)&gt; f3(&amp;test, &amp;Test::intmem1);</font></p> <p><font face="Consolas">f1(1);<br>f1_(1);<br>f2(2);<br>f3(3);</font></p> <p>当然，void 函数也是支持的。</p> <p>观察上面的这些代码，和我们在上一篇中的代码高度一致，不同的是那些模版参数、偏特化参数、函数调用参数等地方。</p> <p>假如有这么一组宏：<br>TYPENAME_DECLARE(n) 被定义为 typename T0, typename T1, …, typename Tn<br>TYPENAME_LIST(n) 被定义为 T0, T1, …, Tn<br>TYPENAME_VARIABLE(n) 被定义为 T0 v0, T1 v1, …, Tn vn<br>VARIABLE_LIST(n) 被定义为 v0, v1, …, vn</p> <p>那么我们可以使用一个 n 就写出支持所有具有参数的函数的 Function 了。我们抛弃掉上面的 1 系列的所有类，仅保持上篇留下来的代码，然后利用上面 4 个宏将所有数字尾巴去掉，于是代码变成：</p> <p><font face="Consolas">template &lt;typename R, TYPENAME_DECLARE(n)&gt;<br>class FunctionBase_##n<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual R Invoke(TYPENAME_LIST(n)) = 0;<br>&nbsp;&nbsp;&nbsp; virtual ~FunctionBase_##n() {}<br>};</font></p> <p><br><font face="Consolas">template &lt;typename R, TYPENAME_DECLARE(n), typename T&gt;<br>class Function_##n : public FunctionBase_##n&lt;R, TYPENAME_LIST(n)&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke(TYPENAME_VARIABLE(n))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_Fun(VARIABLE_LIST(n));<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; Function_##n(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_Fun(fun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; T m_Fun;<br>};</font></p> <p><font face="Consolas">template &lt;typename R, typename P, typename T, TYPENAME_DECLARE(n)&gt;<br>class MemberFunction_##n : public FunctionBase_##n&lt;R, TYPENAME_LIST(n)&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke(TYPENAME_VARIABLE(n))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (m_pObj-&gt;*m_pMemFun)(VARIABLE_LIST(n));<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; MemberFunction_##n(P pObj, R (T::*pMemFun)(TYPENAME_LIST(n)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pObj(pObj), m_pMemFun(pMemFun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; R (T::*m_pMemFun)(TYPENAME_LIST(n));<br>&nbsp;&nbsp;&nbsp; P m_pObj;<br>};</font></p> <p><font face="Consolas">template &lt;typename RetType, TYPENAME_DECLARE(n)&gt;<br>struct FunctionTraits&lt;RetType (TYPENAME_LIST(n))&gt;<br>{<br>&nbsp;&nbsp;&nbsp; typedef RetType (&amp;ParamType)(TYPENAME_LIST(n));<br>};</font></p> <p><font face="Consolas">template &lt;typename R, TYPENAME_DECLARE(n)&gt;<br>class Function&lt;R (TYPENAME_LIST(n))&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new Function_##n&lt;R, TYPENAME_LIST(n), typename FunctionTraits&lt;T&gt;::ParamType&gt;(fun))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; template &lt;typename P, typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(P pObj, R (T::*pMemFun)(TYPENAME_LIST(n)))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new MemberFunction_##n&lt;R, P, T, TYPENAME_LIST(n)&gt;(pObj, pMemFun))<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; ~Function()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete m_pFunBase;<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; R operator ()(TYPENAME_VARIABLE(n))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_pFunBase-&gt;Invoke(VARIABLE_LIST(n));<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; FunctionBase_##n&lt;R, TYPENAME_LIST(n)&gt; *m_pFunBase;<br>};</font></p> <p>当然上面这样子的代码是没法跑的咯。如果我们将整段代码定义为一个宏 BODY(n)，然后用类似刚才四个宏的方式定义宏 FUNCTION_IMPLEMENT(n)，使得它的含义为 BODY(0), BODY(1), …, BODY(n)，所有工作就都完成了。最后只需要丢下一句 FUNCTION_IMPLEMENT(20)，就可以支持 0 到 21 个参数了。</p> <p>最后归结为，如何使用宏搞出“T0, T1, …, Tn” 的形式。</p> <p>暴力点，我们可以这样：</p> <p><font face="Consolas">#define T_0 T0<br>#define T_1 T_0, T1<br>#define T_2 T_1, T2<br>#define T_3 T_2, T3<br>#define T_4 T_3, T4<br>#define T_5 T_4, T5<br>#define T_6 T_5, T6<br>#define T_7 T_6, T7<br>#define T_8 T_7, T8<br>#define T_9 T_8, T9</font></p> <p><font face="Consolas">#define T(n) T_##n<br></font></p> <p>这样子，对于上面四个宏可以，但是对于最后的 X(n)，人工代码量还是太大了。嗯？X(n)？对，这个 X，必须在 _1、_2、_3 系列宏里面占据一个参数地位，这样才有那么一点点扩展性。考虑换成这样：</p> <p><font face="Consolas">#define REP_0(macro, n) macro(0)<br>#define REP_1(macro, n) REP_0(macro, n), macro(1)<br>#define REP_2(macro, n) REP_1(macro, n), macro(2)<br>#define REP_3(macro, n) REP_2(macro, n), macro(3)<br>#define REP_4(macro, n) REP_3(macro, n), macro(4)<br>#define REP_5(macro, n) REP_4(macro, n), macro(5)<br>#define REP_6(macro, n) REP_5(macro, n), macro(6)<br>#define REP_7(macro, n) REP_6(macro, n), macro(7)<br>#define REP_8(macro, n) REP_7(macro, n), macro(8)<br>#define REP_9(macro, n) REP_8(macro, n), macro(9)</font></p> <p><font face="Consolas">#define REP(macro, n)&nbsp;&nbsp; REP_##n(macro, n)</font></p> <p>然后：</p> <p><font face="Consolas">#define TYPENAME_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp; T##n<br>#define TYPENAME_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_LIST_PATTERN, n)<br></font></p> <p>这个 TYPENAME_LIST 就是符合上文要求的宏。接下来如法炮制其余三个：</p> <p><font face="Consolas">#define TYPENAME_DECLARE_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp; typename T##n<br>#define TYPENAME_DECLARE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_DECLARE_PATTERN, n)</font></p> <p><font face="Consolas">#define TYPENAME_VARIABLE_PATTERN(n)&nbsp;&nbsp;&nbsp; T##n v##n<br>#define TYPENAME_VARIABLE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_VARIABLE_PATTERN, n)</font></p> <p><font face="Consolas">#define VARIABLE_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v##n<br>#define VARIABLE_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(VARIABLE_LIST_PATTERN, n)</font></p> <p>最后，我们在 #define FUNCTION_IMPLEMENT(n)&nbsp; REP(BODY, n) 中还存在一点点问题。因为 BODY 中会含有 TYPENAME_DECLARE 之类的宏的使用，而 TYPENAME_DECLARE 正是使用 REP 定义的。这涉及到宏的递归展开，C++预处理器的规则是，遇到这样的情况就停止展开。比如，我们 定义 BODY(n) 为 TYPENAME_DECLARE(n)，于是 FUNCTION_IMPLEMENT(2) 会被展成：</p> <p><font face="Consolas">REP(TYPENAME_DECLARE_PATTERN, 0), REP(TYPENAME_DECLARE_PATTERN, 1), REP(TYPENAME_DECLARE_PATTERN, 2)</font></p> <p>上面的 REP 不会被继续展开了。</p> <p>为此，一个不太聪明的办法就是，再定义一组 REP2。嗯，是个办法，就这么办吧。另外我们刚才的 REP 系列没有将分隔符作为参数，默认使用逗号，而最后一不的 FUNCTION_IMPLEMENT 的重复中是不能用逗号的。考虑提取出来作为参数。最后我们的所需要的宏系统是：</p> <p><font face="Consolas">#define NIL<br>#define COMMA ,</font></p> <p><font face="Consolas">#define REP_0(macro, splitter, n) macro(0)<br>#define REP_1(macro, splitter, n) REP_0(macro, splitter, n) splitter macro(1)<br>#define REP_2(macro, splitter, n) REP_1(macro, splitter, n) splitter macro(2)<br>#define REP_3(macro, splitter, n) REP_2(macro, splitter, n) splitter macro(3)<br>#define REP_4(macro, splitter, n) REP_3(macro, splitter, n) splitter macro(4)<br>#define REP_5(macro, splitter, n) REP_4(macro, splitter, n) splitter macro(5)<br>#define REP_6(macro, splitter, n) REP_5(macro, splitter, n) splitter macro(6)<br>#define REP_7(macro, splitter, n) REP_6(macro, splitter, n) splitter macro(7)<br>#define REP_8(macro, splitter, n) REP_7(macro, splitter, n) splitter macro(8)<br>#define REP_9(macro, splitter, n) REP_8(macro, splitter, n) splitter macro(9)</font></p> <p><font face="Consolas">#define REP(macro, splitter, n)&nbsp;&nbsp; REP_##n(macro, splitter, n)</font></p> <p><font face="Consolas">#define REP2_0(macro, splitter, n) macro(0)<br>#define REP2_1(macro, splitter, n) REP2_0(macro, splitter, n) splitter macro(1)<br>#define REP2_2(macro, splitter, n) REP2_1(macro, splitter, n) splitter macro(2)<br>#define REP2_3(macro, splitter, n) REP2_2(macro, splitter, n) splitter macro(3)<br>#define REP2_4(macro, splitter, n) REP2_3(macro, splitter, n) splitter macro(4)<br>#define REP2_5(macro, splitter, n) REP2_4(macro, splitter, n) splitter macro(5)<br>#define REP2_6(macro, splitter, n) REP2_5(macro, splitter, n) splitter macro(6)<br>#define REP2_7(macro, splitter, n) REP2_6(macro, splitter, n) splitter macro(7)<br>#define REP2_8(macro, splitter, n) REP2_7(macro, splitter, n) splitter macro(8)<br>#define REP2_9(macro, splitter, n) REP2_8(macro, splitter, n) splitter macro(9)</font></p> <p><font face="Consolas">#define REP2(macro, splitter, n)&nbsp;&nbsp; REP2_##n(macro, splitter, n)</font></p> <p><font face="Consolas">#define TYPENAME_DECLARE_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp; typename T##n<br>#define TYPENAME_DECLARE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_DECLARE_PATTERN, COMMA, n)</font></p> <p><font face="Consolas">#define TYPENAME_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T##n<br>#define TYPENAME_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_LIST_PATTERN, COMMA, n)</font></p> <p><font face="Consolas">#define TYPENAME_VARIABLE_PATTERN(n)&nbsp;&nbsp;&nbsp; T##n v##n<br>#define TYPENAME_VARIABLE(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(TYPENAME_VARIABLE_PATTERN, COMMA, n)</font></p> <p><font face="Consolas">#define VARIABLE_LIST_PATTERN(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v##n<br>#define VARIABLE_LIST(n)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REP(VARIABLE_LIST_PATTERN, COMMA, n)</font></p> <p><font face="Consolas">#define FUNCTION_IMPLEMENT(n)&nbsp; REP2(BODY, NIL, n)</font></p> <p>最后，定义一下 FUNCTION_IMPLEMENT(5)，就可以支持到 6 个参数了。为了支持更多参数，把上面的 REP 以及 REP2 系列多定义一点，比如到 50，那么 FUNCTION_IMPLEMENT 的括号中就可以填 50 以内的任意数了。考虑到宏展开对编译速度的影响，以及实际应用中函数参数的个数，定为 20 左右比较合适。</p> <p>到这里，我们的Function已经实现了预期目标。接下来我本来想说说 TypeList 的。可是现在发现没有 TypeList，Function 跑的通；有了 TypeList，Function 也不能写的漂亮多少，虽说那些重复部分有一定的减少。Loki 的 Functor 的参数类型是一个返回值类型加上一个 TypeList，是由用户直接传入 TypeList 的，不用由散的类型组合出一个TypeList（但还是要从TypeList中萃取各个参数类型），因此用在他那里看上去美妙一点点。当然，Loki 也在 Functor 外头包了一层 Function，以支持函数签名作为模版参数的使用方式。有一点不算改观的改观是，用了 TypeList 以后，就不会再有 FunctionBase_1, FunctionBase_2 这样的玩意儿了，取而代之的是一个统一的 FunctionBase 外加许多偏特化版本，Function* 和 MemberFunction* 可以分别统一为一个，但是每一个里头都需要实现 N 个 Invoke。加上篇幅关系，我想这里就不说这个 TypeList 了。</p> <p>代码清单太长了，就不贴了，有意者自然能凑起来。我目前在 xlLib 中的最终实现见 <a title="xlFunction.h" href="http://xllib.codeplex.com/SourceControl/changeset/view/6097#124213" target="_blank">xlFunction.h</a>。</p> <p>关于宏，我不知道可以怎样改进。BOOST_PP_REPEAT 貌似可以调用自身？不知道如何实现的，求指教。另外<a href="http://www.cppblog.com/vczh" target="_blank">@vczh</a>貌似说“实现了一门可以自己递归自己和内置列表处理的另一个宏”，求分享呀求分享。</p> <p><font color="#f79646"><strong>2010-01-18 补充：将最外层 Function 的构造函数中的 const T &amp; 直接改为 T，并且抛弃 FunctionTraits，函数实体类型将在传递过程中直接退化为函数指针，这样就能特化出正确的 FunctionHandler。同时带来另一点影响：如果传入 Functor，字面上将多一次拷贝动作。抛开这一点微小的性能来讲，这比刚才的 FunctionTraints 要好得多了。</strong></font></p><img src ="http://www.cppblog.com/Streamlet/aggbug/138693.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-01-17 21:59 <a href="http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 下 Function 对象的实现（上）</title><link>http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html</link><dc:creator>溪流</dc:creator><author>溪流</author><pubDate>Sun, 16 Jan 2011 14:17:00 GMT</pubDate><guid>http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html</guid><wfw:comment>http://www.cppblog.com/Streamlet/comments/138615.html</wfw:comment><comments>http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html#Feedback</comments><slash:comments>55</slash:comments><wfw:commentRss>http://www.cppblog.com/Streamlet/comments/commentRss/138615.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Streamlet/services/trackbacks/138615.html</trackback:ping><description><![CDATA[<p>目录：</p> <p><a href="http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html" target="_blank">C++ 下 Function 对象的实现（上）</a><br><a href="http://www.cppblog.com/Streamlet/archive/2011/01/17/138693.html" target="_blank">C++ 下 Function 对象的实现（下）</a></p> <p>起因在<a href="http://www.cppblog.com/Streamlet/archive/2011/01/16/138609.html" target="_blank">上一篇</a>已经说过了。现在让我们直接进入主题。本文的目标是，让以下代码能顺利跑起来：</p> <p><font face="Consolas">int intfun0()<br>{<br>&nbsp;&nbsp;&nbsp; return 1;<br>}</font></p> <p><font face="Consolas">struct _intfunctor0<br>{<br>&nbsp;&nbsp;&nbsp; int operator()()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 2;<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">} intfunctor0;</font></p> <p><font face="Consolas">struct Test<br>{<br>&nbsp;&nbsp;&nbsp; int intmem0()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 3;<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">} test;</font></p> <p><font face="Consolas">int main()<br>{<br>&nbsp;&nbsp;&nbsp; Function&lt;int ()&gt; f1(&amp;intfun0);<br>&nbsp;&nbsp;&nbsp; Function&lt;int ()&gt; f1_(intfun0);<br>&nbsp;&nbsp;&nbsp; Function&lt;int ()&gt; f2(intfunctor0);<br>&nbsp;&nbsp;&nbsp; Function&lt;int ()&gt; f3(&amp;test, &amp;Test::intmem0);</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; f1();<br>&nbsp;&nbsp;&nbsp; f1_();<br>&nbsp;&nbsp;&nbsp; f2();<br>&nbsp;&nbsp;&nbsp; f3();</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; return 0;<br>}</font><br></p> <p>除了上述例子中显示的，还要支持有返回值的函数和没返回值的函数，以及有0个、1个、2个、……、MAX 个参数的函数，参数类型无限制。最后实现的 Function 对象仅仅可以执行就好。（至于是否可拷贝、是否可判断相等 等问题，都是小事，本文暂不考虑。）最后，Bind 概念也不在本文讨论范围之内。</p> <p>对于这个问题，我们一开始考虑的可能是怎样统一三种不同形式。有两个选择，第一，使用 C++ 的多态机制，最后统一到基类指针的类型；第二，允许类内部有冗余变量以及必要的 Flag，用于判断是哪种形式的函数，要如何执行。这样看起来，第一种方案比第二种爽一点。于是，最初想到的实现有可能是这样的：</p> <p>先定义一个虚基类：</p> <p><font face="Consolas">template &lt;typename R&gt;<br>class FunctionBase0<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; virtual R Invoke() = 0;<br>&nbsp;&nbsp;&nbsp; virtual ~FunctionBase0() {}<br>};<br></font></p> <p>然后实现一个普通函数/仿函数的版本：</p> <p><font face="Consolas">template &lt;typename R, typename T&gt;<br>class Function0 : public FunctionBase0&lt;R&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_Fun();<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; Function0(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_Fun(fun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; T m_Fun;<br>};</font></p> <p>这里需要说明的是，如果是普通函数，T会被特化成 R() 或者 R (&amp;)() 或者 R(*)()，取决于使用的时候传入 fun 还是传入 &amp;fun。所以不必另外实现针对 R(*)() 的版本。Loki （姑且就以作品名称乎 Loki 的作者吧，他那个真名实在是太长）在他的书中称之为“<font face="Consolas">做一个，送一个</font>”。不过对于他书中所说的，我有一个疑惑。Loki 说传入 fun，模版参数 T 会被特化成 R (&amp;)()，于是一切顺利。可是我在操作过程中发现 T 一直被特化成 R ()，于是上述 class 中的 m_Fun 被认为是成员函数而不是成员变量。不知道是为什么，<strong>有知道者请不吝指教</strong>哈。因为以上原因，本文中我一直用 &amp;fun 的形式对待普通函数。</p> <p>再实现一个成员函数的版本：</p> <p><font face="Consolas">template &lt;typename R, typename T&gt;<br>class MemberFunction0 : public FunctionBase0&lt;R&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; R Invoke()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (m_pObj-&gt;*m_pMemFun)();<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">public:<br>&nbsp;&nbsp;&nbsp; MemberFunction0(T *pObj, R (T::*pMemFun)())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pObj(pObj), m_pMemFun(pMemFun)<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; R (T::*m_pMemFun)();<br>&nbsp;&nbsp;&nbsp; T *m_pObj;<br>};<br></font></p> <p>最后是一个包装类。如果你可以接受 Function&lt;int&gt; 表示 int()， Function&lt;int, int&gt; 表示 int (int)，…，那么这里没有多少技巧可言。boost 的那个 function 使用的是函数签名作为模版参数，即 Function&lt;int()&gt;，Function&lt;int (int)&gt; 等形式。如果不太研究语法，可能会像我一样，一开始会对尖括号里的 int (int) 之类的玩意儿不太熟悉，觉得很牛逼。可是了解了以后，不过是个函数类型而已，没什么大不了的。Loki 的 Functor 的使用方式是 Functor&lt;int, TYPELIST_0()&gt;，Functor&lt;int, TYPELIST_1(int)&gt;。其中第一个模版参数始终是返回值，第二个模版参数是参数类型列表，Loki 使用了他创造的玩意儿 TypeList 使得所有函数参数只占一个坑，这在等下的支持多参数的扩展中能够带来一些美观。我比较喜欢 boost 的使用方式，让使用者直接以语言规定的形式填入函数签名，而不是一些额外的约定（“第一个模版参数表示返回值”，“第二个到最后的模版参数表示参数”，“第二个模版参数以 TypeList 形式表示函数参数”等）。</p> <p>为了达到这个目标，我们要玩一些偏特化技巧。关于偏特化，我一直以来的肤浅认识都是错误的。我原以为，对于模版类：</p> <p><font face="Consolas">template &lt;typename T0, typename T1&gt;<br>class Foo;</font></p> <p>我如果特化其中一个参数 T1：</p><font face="Consolas">template &lt;typename T0&gt;<br>class Foo&lt;T0, int&gt;<br>{<br><br>}</font>  <p>我以为只有这样才叫偏特化，以为偏特化的过程总是减少模版参数的。而实际上，只要用某个/些类型占据原始模版参数的位置，就可以了。比如，对于上述 Foo，我可以特化一个 class&lt;T0, std::map&lt;U0, U1&gt;&gt;，消去一个 T1，而新增 U0、U1：</p><font face="Consolas">template &lt;typename T0, typename U0, typename U1&gt;<br>class Foo&lt;T0, std::map&lt;U0, U1&gt;&gt;<br>{<br><br>}</font>  <p>原来 T1 的位置被 std::map&lt;U0, U1&gt; 占据了，这也是偏特化。当然最后的模版参数数量也可以不变，如：</p><font face="Consolas">template &lt;typename T0, typename U&gt;<br>class Foo&lt;T0, std::vector&lt;U&gt;&gt;<br>{<br><br>}</font>  <p>以及</p><font face="Consolas">template &lt;typename T0, typename U&gt;<br>class Foo&lt;T0, U*&gt;<br>{<br><br>}</font>  <p>其中后者是实现类型萃取的主要方式。只要特化以后，这个类依然带有至少一个模版参数，就是偏特化。如果最后产生了 template&lt;&gt; 的形式，那就是完全特化。</p> <p>回到我们刚才的主题，我们要提供给用户的是这样一个类：</p> <p><font face="Consolas">template &lt;typename Signature&gt;<br>class Function;</font></p> <p>其中参数 Signature 会被实际的函数类型所特化。但是我们只知道整体的一个 Signature 并没有用，我们必须知道被分解开来的返回值类型、参数类型。于是，引入一个偏特化版本：</p> <p><font face="Consolas">template &lt;typename R&gt;<br>class Function&lt;R ()&gt;<br></font></p> <p>这里使用 R () 特化原始的 Signature，引入一个新的参数 R。于是返回值类型 R 就被萃取出来了。实现如下：</p> <p><font face="Consolas">template &lt;typename R&gt;<br>class Function&lt;R ()&gt;<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new Function0&lt;R, T&gt;(fun))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(T *pObj, R (T::*pMemFun)())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new MemberFunction0&lt;R, T&gt;(pObj, pMemFun))<br>&nbsp;&nbsp;&nbsp; {</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; ~Function()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete m_pFunBase;<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; R operator ()()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m_pFunBase-&gt;Invoke();<br>&nbsp;&nbsp;&nbsp; }</font></p> <p><font face="Consolas">private:<br>&nbsp;&nbsp;&nbsp; FunctionBase0&lt;R&gt; *m_pFunBase;<br>};</font></p> <p>如果对上面说的“普通函数的使用方式必须是函数指针而不是函数本身”耿耿于怀，可以再引入一个的构造函数：</p> <p><font face="Consolas">typedef R (FunctionType)();</font></p> <p><font face="Consolas">Function(const FunctionType &amp;fun)<br>&nbsp;&nbsp;&nbsp; : m_pFunBase(new Function0&lt;R, FunctionType &amp;&gt;(fun))<br>{</font></p> <p><font face="Consolas">}<br></font></p> <p>这里 FunctionType 是 R(&amp;)() 类型，强制使用它来特化 Function0 中的 T。该构造函数在重载决议中会取得优先权从而使普通函数本身的传入成为可能。不过，以函数本身形式传入的普通函数会丧失一些特性，比如 Function&lt;int()&gt; 只能接受 int() 类型的普通函数而不能接受 char () 型的普通函数，因为这种情况下不会走我们刚才新定义的构造函数。</p> <p>还有一种做法，就是针对全局函数，强制特化出模版参数为其引用类型的类。定义如下元函数：</p> <p><font face="Consolas">template &lt;typename Signature&gt;<br>struct FunctionTraits<br>{<br>&nbsp;&nbsp;&nbsp; typedef Signature ParamType;<br>};<br>&nbsp;&nbsp;&nbsp; <br>template &lt;typename RetType&gt;<br>struct FunctionTraits&lt;RetType ()&gt;<br>{<br>&nbsp;&nbsp;&nbsp; typedef RetType (&amp;ParamType)();<br>};</font></p> <p>然后构造函数改为：</p><font face="Consolas">&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>&nbsp;&nbsp;&nbsp; Function(const T &amp;fun)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : m_pFunBase(new Function0&lt;R, typename FunctionTraits&lt;T&gt;::ParamType&gt;(fun))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; }</font>  <p>用以上方法，所有的特性都不会丢失。</p> <p>到这儿，我们的 Function 已经可以小试牛刀了：</p> <p><font face="Consolas">Function&lt;int ()&gt; f1(&amp;intfun0);<br></font></p><font face="Consolas">Function&lt;int ()&gt; f1_(intfun0);</font><font face="Consolas"><br>Function&lt;int ()&gt; f2(intfunctor0);<br>Function&lt;int ()&gt; f3(&amp;test, &amp;Test::intmem0);</font>  <p><font face="Consolas">f1();<br>f1_();<br>f2();<br>f3();</font></p> <p>上面这段代码已经能够正常运行了。</p> <p>来，继续<strong>做一个，送一个</strong>。下面的代码居然也能跑（voidfun0、voidfunctor0、Test::voidmem0类似int版本定义）：</p><font face="Consolas">Function&lt;void ()&gt; f4(&amp;voidfun0);<br></font><font face="Consolas">Function&lt;void ()&gt; f4_(voidfun0);<br></font><font face="Consolas">Function&lt;void ()&gt; f5(voidfunctor0);<br>Function&lt;void ()&gt; f6(&amp;test, &amp;Test::voidmem0);</font>  <p><font face="Consolas">f4();<br>f4_();<br>f5();<br>f6();<br></font></p> <p>这说明了，在类里面写一个返回值为该类型的函数，并在里面写下 return XXX; 然后以 void 为模版参数传入该模版类，是符合语法的。验证一下：</p> <p><font face="Consolas">template &lt;typename T&gt;<br>class Foo<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; T Bar()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("%s invoked\n", __FUNCTION__);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return T();<br>&nbsp;&nbsp;&nbsp; }<br>};</font></p> <p><font face="Consolas">int main()<br>{<br>&nbsp;&nbsp;&nbsp; Foo&lt;void&gt; f1;<br>&nbsp;&nbsp;&nbsp; f1.Bar();</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; Foo&lt;int&gt; f2;<br>&nbsp;&nbsp;&nbsp; int i = f2.Bar();</font></p> <p><font face="Consolas">&nbsp;&nbsp;&nbsp; return 0;<br>}</font></p> <p>运行结果：</p> <p>Foo&lt;void&gt;::Bar invoked<br>Foo&lt;int&gt;::Bar invoked</p> <p>到此为止，我们已经实现了 0 个参数的函数支持，也即 R () 类型的所有函数的支持。接下来还要实现对具有 1 个、2 个、3 个直至任意有限个参数的函数支持。也许您也发现了，接下来的工作可以是体力活，我们可以照葫芦画瓢，搞出一堆 FunctionBaseN、FunctionN、MemberFunctionN，并在最后的 Function 中再实现 N 个偏特化版本。是，不错，大致上原理就是这样。限于篇幅，我想暂时写到这里，下篇将继续谈谈宏、TypeList，以及怎样少花点力气实现其余 N 个版本。最终达到的效果是，只要改一个宏定义，就可以提高参数上限。</p> <p>在本文所涉及的内容中，我比较纠结的是，可否在不用多态机制的情况下达到比较优雅的形式统一？</p> <p>欢迎讨论。</p><img src ="http://www.cppblog.com/Streamlet/aggbug/138615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Streamlet/" target="_blank">溪流</a> 2011-01-16 22:17 <a href="http://www.cppblog.com/Streamlet/archive/2011/01/16/138615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>