﻿<?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++博客-loop_in_codes-随笔分类-C/C++</title><link>http://www.cppblog.com/kevinlynx/category/6337.html</link><description>低调做技术__
C/C++\MMORPG服务器\模块架构__ TODO：编译原理\linux env __Kevin Lynx</description><language>zh-cn</language><lastBuildDate>Sun, 14 Mar 2010 10:17:15 GMT</lastBuildDate><pubDate>Sun, 14 Mar 2010 10:17:15 GMT</pubDate><ttl>60</ttl><item><title>静态库中全局变量的初始化问题</title><link>http://www.cppblog.com/kevinlynx/archive/2010/01/17/105885.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Sun, 17 Jan 2010 11:34:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2010/01/17/105885.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/105885.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2010/01/17/105885.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/105885.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/105885.html</trackback:ping><description><![CDATA[<p><font size="2"></font>&nbsp; <p><font size="2">在我自己写的一个工厂类实现中，每个产品会注册创建接口到这个工厂类。工厂类使用这些<br>注册进来的创建接口来完成产品的创建。其结构大致如下： </font> <p><font size="2">product *factory::create( long product_type )<br>{<br>&nbsp;&nbsp;&nbsp; creator c = m_creators[product_type];<br>&nbsp;&nbsp;&nbsp; return c();<br>} </font> <p><font size="2">factory::instance().register( PRODUCT_A_TYPE, productA::create );<br>...<br>factory::instance().create( PRODUCT_A_TYPE ); </font> <p><font size="2">这个很普通的工厂实现中，需要写上很多注册代码。每次添加新的产品种类时，也需要修改<br>这些的注册代码。而恰好，这些注册代码可能会被放在一个统一的地方。为了消除这个地方<br>，我使用了偶然间看到的&lt;Modern C++ design&gt;里的做法： </font> <p><font size="2">const bool _local = factory::instance().register( PRODUCT_A_TYPE,... </font> <p><font size="2">也就是说，通过对全局常量_local的自动初始化，来自动完成对该产品的注册。 </font> <p><font size="2">结果，因为这些代码全部被放置于一个静态库。最终的代码文件结构大致为： </font> <p><font size="2">lib<br>&nbsp;&nbsp;&nbsp; - product_a.cpp : 定义了全局常量_local<br>&nbsp;&nbsp;&nbsp; - product_a.h<br>&nbsp;&nbsp;&nbsp; - factory.cpp<br>&nbsp;&nbsp;&nbsp; - factory.h<br>exe<br>&nbsp;&nbsp;&nbsp; - main.cpp </font> <p><font size="2">现在看起来世界很美，因为factory甚至不知道世界上还有个跟上层逻辑相关的product_a。<br>这种模块耦合几乎为0的结构让我窃喜。 </font> <p><font size="2">悲剧的事情首先发生于，开VC调试器，发现打在product_a.cpp里的断点失效。就是那个总<br>是提示说没有为该文件加载调试符号。开始还不在意，以为又是代码和调试符号文件不匹配<br>的原因，折腾了好久，不得其果。 </font> <p><font size="2">后来分析了下，发现这个调试提示，就像我开着调试器打开了一个非本工程的代码文件，而<br>断点就打在这个文件里一样。也就是说，VC把我product_a.cpp当成不是这个工程里的代码<br>文件。 </font> <p><font size="2">按照这个思路写些实验代码，最终发现问题所在：VC链接器根本没链接进product_a.cpp里<br>的代码。表现出来的情况就是，该编译单元里的全局常量（全局变量一样）根本没有得到初<br>始化，因为我跟到factory::register并没有被调用到。为什么VC不链接这个编译单元对应<br>的目标文件？或者说，为什么VC不初始化这个全局常量？ </font> <p><font size="2">原因就在于，product_a.cpp太独立了。一个在整个编译链接阶段都无法确定该文件是否被<br>使用的文件，VC就直接不链接了。相反，当在factory.cpp里写下类似代码： </font> <p><font size="2">void test()<br>{<br>&nbsp;&nbsp;&nbsp; product_a obj;<br>} </font> <p><font size="2">虽然说test函数不会被调用，一切情况也变得正常了。好了，不扯了，给最后我的结论： </font> <p><font size="2">1、如果静态库中某个编译单元在编译阶段被确认为它并没有被外部使用，那么当这个静态<br>库被链接进可执行文件时，链接器忽略掉该编译单元里的代码，那么，链接器自然也不会为<br>该编译单元里出现的全局变量常量生成初始化代码（关于这部分初始化代码可以阅读<br>&lt;linker and loader&gt;一书）；<br>2、上面那条结论存在一种传染性，意思是，当可执行文件里的代码使用到静态库中文件A里<br>的代码，A里又有地方使用到B里的代码，那么B依然会被链接。这种依赖性，应该可以让编<br>译器在编译阶段就发现（显然，上面我举的例子里，factory只有在运行期间才会依赖到<br>product_a.cpp里的代码） </font></p><img src ="http://www.cppblog.com/kevinlynx/aggbug/105885.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2010-01-17 19:34 <a href="http://www.cppblog.com/kevinlynx/archive/2010/01/17/105885.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自己写内存泄露检测库</title><link>http://www.cppblog.com/kevinlynx/archive/2009/01/23/72514.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Fri, 23 Jan 2009 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2009/01/23/72514.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/72514.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2009/01/23/72514.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/72514.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/72514.html</trackback:ping><description><![CDATA[<p><font size=2>author: kevin lynx</font></p>
<p><font size=2>这个内存泄露工具最基本的原理就是利用宏替换掉标准的malloc、free（暂不考虑其他内存分配函数，<br>如realloc、strdup），记录下每次内存分配和释放动作。因为宏的处理发生在预处理阶段，所以可以<br>很容易地用你自己的malloc函数替换掉标准的malloc。例如： </font></p>
<p><font size=2></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_0_10_Open_Image onclick="this.style.display='none'; Codehighlighter1_0_10_Open_Text.style.display='none'; Codehighlighter1_0_10_Closed_Image.style.display='inline'; Codehighlighter1_0_10_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_0_10_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_10_Closed_Text.style.display='none'; Codehighlighter1_0_10_Open_Image.style.display='inline'; Codehighlighter1_0_10_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span id=Codehighlighter1_0_10_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_0_10_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;lib.h&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;malloc&nbsp;my_malloc</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;free&nbsp;my_free&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_60_70_Open_Image onclick="this.style.display='none'; Codehighlighter1_60_70_Open_Text.style.display='none'; Codehighlighter1_60_70_Closed_Image.style.display='inline'; Codehighlighter1_60_70_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_60_70_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_60_70_Closed_Text.style.display='none'; Codehighlighter1_60_70_Open_Image.style.display='inline'; Codehighlighter1_60_70_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_60_70_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_60_70_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;lib.c&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_72_117_Open_Image onclick="this.style.display='none'; Codehighlighter1_72_117_Open_Text.style.display='none'; Codehighlighter1_72_117_Closed_Image.style.display='inline'; Codehighlighter1_72_117_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_72_117_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_72_117_Closed_Text.style.display='none'; Codehighlighter1_72_117_Open_Image.style.display='inline'; Codehighlighter1_72_117_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_72_117_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_72_117_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;disable&nbsp;these&nbsp;macro&nbsp;in&nbsp;this&nbsp;compile&nbsp;unit&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#undef</span><span style="COLOR: #000000">&nbsp;malloc</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#undef</span><span style="COLOR: #000000">&nbsp;free&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;count&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">my_malloc(&nbsp;size_t&nbsp;size&nbsp;)<br><img id=Codehighlighter1_202_244_Open_Image onclick="this.style.display='none'; Codehighlighter1_202_244_Open_Text.style.display='none'; Codehighlighter1_202_244_Closed_Image.style.display='inline'; Codehighlighter1_202_244_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_202_244_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_202_244_Closed_Text.style.display='none'; Codehighlighter1_202_244_Open_Image.style.display='inline'; Codehighlighter1_202_244_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_202_244_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_202_244_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">count;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;malloc(&nbsp;size&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;my_free(&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">a&nbsp;)<br><img id=Codehighlighter1_272_302_Open_Image onclick="this.style.display='none'; Codehighlighter1_272_302_Open_Text.style.display='none'; Codehighlighter1_272_302_Closed_Image.style.display='inline'; Codehighlighter1_272_302_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_272_302_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_272_302_Closed_Text.style.display='none'; Codehighlighter1_272_302_Open_Image.style.display='inline'; Codehighlighter1_272_302_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_272_302_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_272_302_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">count;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;free(&nbsp;a&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>要使用以上代码，用户在使用时就需要包含lib.h，从而可以使用宏将用户自己写的malloc替换<br>为my_mallo。当程序退出时，如果count大于0，那么可以肯定的是有内存泄露。当然，如果<br>count为负数，则很可能对同一个指针进行多次free。 </font>
<p><font size=2>但是以上代码的功能太局限了。一个真正的内存泄露检测库（工具），至少需要报告泄露的代码<br>文件、函数、行数等信息。当然，如果能报告调用堆栈，就更好了。不过这就依赖于具体的平台，<br>需要使用特定的系统接口才可以获取出。 </font>
<p><font size=2>要实现以上功能也很简单，只需要在每次调用malloc的时候，通过编译器预定义宏__FILE__、<br>__LINE__、__FUNCTION__(__func__)就可以得到文件名、函数、行号等信息。将这些信息保存<br>起来，然后在free的时候移除相应的信息即可。 </font>
<p><font size=2>最简单的实现方式，就是保存一个表，表里记录着每次分配内存的信息： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;memRecord<br><img id=Codehighlighter1_17_134_Open_Image onclick="this.style.display='none'; Codehighlighter1_17_134_Open_Text.style.display='none'; Codehighlighter1_17_134_Closed_Image.style.display='inline'; Codehighlighter1_17_134_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_17_134_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_17_134_Closed_Text.style.display='none'; Codehighlighter1_17_134_Open_Image.style.display='inline'; Codehighlighter1_17_134_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_17_134_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_17_134_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;file[MAX_FILE_NAME];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;func[MAX_FUNC_NAME];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;lineno;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">address;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;size;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;memRecord&nbsp;mem_record[MAX_RECORD];&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p></font>&nbsp;
<p><font size=2>但是，通过单单一个free函数的void*参数，如何获取出对应的分配记录呢？难道：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;size_t&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;MAX_RECORD;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;i&nbsp;)<br><img id=Codehighlighter1_42_119_Open_Image onclick="this.style.display='none'; Codehighlighter1_42_119_Open_Text.style.display='none'; Codehighlighter1_42_119_Closed_Image.style.display='inline'; Codehighlighter1_42_119_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_42_119_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_42_119_Closed_Text.style.display='none'; Codehighlighter1_42_119_Open_Image.style.display='inline'; Codehighlighter1_42_119_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_42_119_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_42_119_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;address&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;mem_record[i].address&nbsp;)&nbsp;<br><img id=Codehighlighter1_92_117_Open_Image onclick="this.style.display='none'; Codehighlighter1_92_117_Open_Text.style.display='none'; Codehighlighter1_92_117_Closed_Image.style.display='inline'; Codehighlighter1_92_117_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_92_117_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_92_117_Closed_Text.style.display='none'; Codehighlighter1_92_117_Open_Image.style.display='inline'; Codehighlighter1_92_117_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_92_117_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_92_117_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_102_111_Open_Image onclick="this.style.display='none'; Codehighlighter1_102_111_Open_Text.style.display='none'; Codehighlighter1_102_111_Closed_Image.style.display='inline'; Codehighlighter1_102_111_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_102_111_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_102_111_Closed_Text.style.display='none'; Codehighlighter1_102_111_Open_Image.style.display='inline'; Codehighlighter1_102_111_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_102_111_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_102_111_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;shit&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>虽然可行，但是很stupid。这里提供一个小技巧： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">my_malloc(&nbsp;size_t&nbsp;size&nbsp;)<br><img id=Codehighlighter1_31_122_Open_Image onclick="this.style.display='none'; Codehighlighter1_31_122_Open_Text.style.display='none'; Codehighlighter1_31_122_Closed_Image.style.display='inline'; Codehighlighter1_31_122_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_31_122_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_31_122_Closed_Text.style.display='none'; Codehighlighter1_31_122_Open_Image.style.display='inline'; Codehighlighter1_31_122_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_31_122_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_31_122_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">a&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;malloc(&nbsp;size&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(&nbsp;size_t&nbsp;)&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)a&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(&nbsp;size_t&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;my_free(&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">a&nbsp;)<br><img id=Codehighlighter1_150_265_Open_Image onclick="this.style.display='none'; Codehighlighter1_150_265_Open_Text.style.display='none'; Codehighlighter1_150_265_Closed_Image.style.display='inline'; Codehighlighter1_150_265_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_150_265_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_150_265_Closed_Text.style.display='none'; Codehighlighter1_150_265_Open_Image.style.display='inline'; Codehighlighter1_150_265_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_150_265_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_150_265_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_156_198_Open_Image onclick="this.style.display='none'; Codehighlighter1_156_198_Open_Text.style.display='none'; Codehighlighter1_156_198_Closed_Image.style.display='inline'; Codehighlighter1_156_198_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_156_198_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_156_198_Closed_Text.style.display='none'; Codehighlighter1_156_198_Open_Image.style.display='inline'; Codehighlighter1_156_198_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_156_198_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_156_198_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;actually,&nbsp;'a'&nbsp;is&nbsp;not&nbsp;the&nbsp;real&nbsp;address&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;((</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)a&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(&nbsp;size_t&nbsp;)&nbsp;);&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;free(&nbsp;p&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;</font>
<p><font size=2>意思就是说，我多分配了4字节内存（sizeof( size_t ) ），用于保存这次分配记录在mem_record<br>中被保存的索引。在释放内存的时候，通过一些地址偏移计算，就可以获取出真正的系统malloc<br>返回的地址，从而安全释放（别给我说这里的计算存在平台和编译器的限制，没认真看文章的SB才说）。 </font>
<p><font size=2>另一个问题是，我们如何处理每次分配释放时，对于分配记录那个数据结构，也就是mem_record。<br>每一次free的时候，移除的记录可能位于mem_record的任何位置。一定时间后，mem_record内部<br>将出现很多漏洞（已经没用的数组位置）。解决这个问题最直接当然还是最stupid的方法，就是每次<br>free移除记录时重新整理一遍mem_record。如果你这样做了，那你的malloc/free比微软的还慢。 </font>
<p><font size=2>我的解决方法是：<br>size_t free_index[MAX_RECORD];<br>用于保存这些出现漏洞的index。每一次free移除记录时，就把这个记录对应的inex保存进来，表示<br>这个index指向的mem_record[]可用。每一次malloc的时候，先从这里取index，如果这里没有，那<br>可以直接从mem_record的末尾取。 </font>
<p><font size=2>具体细节就不阐述了，典型的空间换时间方法。整个库很简单，代码100来行。我也只进行过粗略的<br>测试。我肯定这100来行代码是有问题的，相信自己的代码存在问题是对bug的一种觉悟，哈哈哈。 </font>
<p><font size=2>这个东西只检测C语言的内存泄露，其实要检测C++的也很简单，只需要重载new和delete就可以了。 </font>
<p><font size=2>要放春节假了，在公司的最后几个小时实在无聊，才做了这个东西，前后花了1个多小时，写起来感觉<br>不错。</font></p>
<p><font size=2></font>&nbsp;</p>
<p><font size=2></font>&nbsp;</p>
<a href="http://www.cppblog.com/Files/kevinlynx/cmlc.zip" target=_blank>代码下载</a>
<p><font size=2></font>&nbsp;</p>
<p><font size=2></font></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/72514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2009-01-23 17:43 <a href="http://www.cppblog.com/kevinlynx/archive/2009/01/23/72514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最近的两个问题：less for std::map，静态变量初始化顺序</title><link>http://www.cppblog.com/kevinlynx/archive/2008/11/11/66623.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Tue, 11 Nov 2008 09:55:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/11/11/66623.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/66623.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/11/11/66623.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/66623.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/66623.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt"><br>说下最近自己遇到的两个值得让人注意的问题。<br>其一是关于自己给std::map写less predicate，std::map第三个参数是一个典型的functor。map内部将使用<br>这个functor去判定两个元素是否相等，默认使用的是std::less。但是为什么传入的是一个判断第一个参数<br>小于第二个参数的functor，而不是一个判断两个参数是否相等的functor？按照STL文档的说法，当检查两<br>个参数没有小于也没有大于的关系时，就表示两个参数相等。不管怎样，我遇到了需要自己写这个functor<br>的需求，于是：</p>
<p style="FONT-SIZE: 10pt">struct MyLess<br>{<br>&nbsp;&nbsp;&nbsp; bool operator() ( long left, long right )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //...<br>&nbsp;&nbsp;&nbsp; }<br>};</p>
<p style="FONT-SIZE: 10pt">DEBUG模式下编译没问题，RELEASE模式下却出现C3848的错误。这就有点奇怪了，如果确实存在语法错误，<br>那么DEBUG和RELASE应该一样才对。查了下MSDN，C3848的错误是因为const限定符造成的，如：</p>
<p style="FONT-SIZE: 10pt">const MyLess pr;<br>pr(); // C3848</p>
<p style="FONT-SIZE: 10pt">于是，在operator()后加上const，就OK了。看了下VC std::map相关代码，以为是DEBUG和RELEASE使用了不<br>同的代码造成。但是我始终没找到不同点。另一方面，就STL内部的风格来看，应该不会把predicator处理<br>成const &amp;之类的东西，全部是value形式的。奇怪了。</p>
<p style="FONT-SIZE: 10pt">第二个问题，涉及到静态变量。这个东西给我的印象特别深刻，因为以前去一家外企应聘时被问到，当时<br>觉得那个LEADER特别厉害。回来后让我反思，是不是过多地关注了C++里的花哨，而漏掉了C里的朴素？导致<br>我至今对纯C存在偏好。</p>
<p style="FONT-SIZE: 10pt">说正题，我现在有如下的文件关系：</p>
<p style="FONT-SIZE: 10pt">// def.h<br>struct Obj<br>{<br>&nbsp;&nbsp;&nbsp; Obj()<br>&nbsp;{<br>&nbsp;&nbsp;ObjMgr::AddObj( id, this );<br>&nbsp;}<br>&nbsp;int id;<br>};</p>
<p style="FONT-SIZE: 10pt">struct ObjMgr<br>{<br>&nbsp;&nbsp;&nbsp; static void AddObj( int id, Obj *t )<br>&nbsp;{<br>&nbsp;&nbsp;ObjTable[id] = t;<br>&nbsp;}<br>&nbsp;static std::map&lt;int, Obj*&gt; ObjTable;<br>};</p>
<p style="FONT-SIZE: 10pt">static Obj _t;</p>
<p style="FONT-SIZE: 10pt">// ObjMgr.cpp<br>#include "def.h"</p>
<p style="FONT-SIZE: 10pt">static std::map&lt;int, Obj*&gt;::ObjMgr ObjTable;</p>
<p style="FONT-SIZE: 10pt">// main.cpp<br>#include "def.h"</p>
<p style="FONT-SIZE: 10pt">这里举的例子可能有点不恰当，我在一台没有编译器的机器上写的这篇文章。忽略掉这些旁支末节。我的意思，<br>就是想让Obj自己自动向ObjMgr里添加自己。我们都知道静态变量将在程序启动时被初始化，先于main执行之前。</p>
<p style="FONT-SIZE: 10pt">上面代码有两个问题：</p>
<p style="FONT-SIZE: 10pt">一、<br>代码没有按照我预期地执行，如果你按照我的意思做个测试，你的程序甚至在进main之前就crash了。我假定你<br>用的是VC，因为我没在其他编译器上试验过。问题就在于，Obj的构造依赖于ObjTable这个map对象。在调试过程<br>中我发现，虽然ObjTable拥有了内存空间，其this指针有效，但是，map对象并没有得到构造。我的意思是，Obj<br>的构造先于ObjTable构造（下几个断点即可轻易发现），那么在执行map::operator[]时，就出错了，因为这个时候<br>map里相关数据还没准备好。</p>
<p style="FONT-SIZE: 10pt">那是否存在某种机制可以手动静态变量的初始化顺序呢？不知道。我最后怎样解决这个问题的？</p>
<p style="FONT-SIZE: 10pt">二、<br>在还没有想到解决办法之前（不改变我的设计），我发现了这段代码的另一个问题：我在头文件里定义了静态<br>变量：static Obj _t; 这有什么问题？想想预编译这个过程即可知道，头文件在预编译阶段被文本展开到CPP<br>文件里，然后，ObjMgr.cpp和main.cpp文件里都将出现static Obj _t;代码。也就是说，ObjMgr.obj和main.obj<br>里都有一个文件静态变量_t。</p>
<p style="FONT-SIZE: 10pt">看来，在头文件里放这个静态变量是肯定不对的。于是，我将_t移动到ObjMgr.cpp里：</p>
<p style="FONT-SIZE: 10pt">// ObjMgr.cpp<br>#include "def.h"</p>
<p style="FONT-SIZE: 10pt">static std::map&lt;int, Obj*&gt;::ObjMgr ObjTable;<br>static Obj _t;</p>
<p style="FONT-SIZE: 10pt">按照这样的顺序定义后，_t的构造居然晚于ObjTable了。也就是说，放置于前面的变量定义，就意味着它将被<br>首先构造初始化。这样两个问题都解决了。</p>
<p style="FONT-SIZE: 10pt">但是，谁能保证这一点特性？C标准文档里？还是VC编译器自己？</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt"><br>&nbsp;</p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/66623.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-11-11 17:55 <a href="http://www.cppblog.com/kevinlynx/archive/2008/11/11/66623.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让人无语的boost</title><link>http://www.cppblog.com/kevinlynx/archive/2008/10/15/64013.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 15 Oct 2008 03:23:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/10/15/64013.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/64013.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/10/15/64013.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/64013.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/64013.html</trackback:ping><description><![CDATA[<p><font size=2>&nbsp;&nbsp;&nbsp; 关于BOOST，撞车，严重撞车。每一次都让我有点无语。<br>&nbsp;&nbsp;&nbsp; 第一次是我所谓的宏递归，其实就是一个macro library，有一天就不小心在BOOST的library list上<br>看到了这个东西。当然，BOOST很牛，别人的这个macro是真的library。但是，我们的需求撞车，我们的<br>实现手段撞车。于是下定决心下次想要实现个什么东西的时候，先去看看BOOST，可以省掉不少脑力。<br>&nbsp;&nbsp;&nbsp; 本来就没有做好，何必吃力不讨好？<br>&nbsp;&nbsp;&nbsp; 第二次，当我写下类似的模板代码时：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;func(&nbsp;_Tp&nbsp;t&nbsp;);</span></div>
<p><br>&nbsp;&nbsp;&nbsp; 我总要花掉几秒钟时间去决策func的参数是用_Tp&amp;还是_Tp，也就是所谓的究竟是按值传送还是按引用<br>传送。如果按值传送，当_Tp为一个类时，复制的东西过多时，显然效率上过不去。作为func的实现者，良<br>心上更过不去。后来一想，STL的各种算法里到处都是按值传送，这样做总有它的理由吧？<br>&nbsp;&nbsp;&nbsp; 但是，这样做就是不够完美。<br>&nbsp;&nbsp;&nbsp; 于是想起了boost::ref。但是这个时候我并不知道boost::ref是个什么东西。我只是以前在各种地方<br>看到过这个东西。我还是决定自己实现一个。<br>&nbsp;&nbsp;&nbsp; 实现一个什么？考虑有：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;func(&nbsp;_Tp&nbsp;t&nbsp;);</span></div>
<p><br>&nbsp;&nbsp;&nbsp; 而我这个时候要传递一个类对象过去CBaseObject obj。为了效率，我写下如下的代码：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;ref_wrapper<br><img id=Codehighlighter1_54_198_Open_Image onclick="this.style.display='none'; Codehighlighter1_54_198_Open_Text.style.display='none'; Codehighlighter1_54_198_Closed_Image.style.display='inline'; Codehighlighter1_54_198_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_54_198_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_54_198_Closed_Text.style.display='none'; Codehighlighter1_54_198_Open_Image.style.display='inline'; Codehighlighter1_54_198_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_54_198_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_54_198_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_111_113_Open_Image onclick="this.style.display='none'; Codehighlighter1_111_113_Open_Text.style.display='none'; Codehighlighter1_111_113_Closed_Image.style.display='inline'; Codehighlighter1_111_113_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_111_113_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_111_113_Closed_Text.style.display='none'; Codehighlighter1_111_113_Open_Image.style.display='inline'; Codehighlighter1_111_113_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ref_wrapper(&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p&nbsp;)&nbsp;:&nbsp;_obj(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">p&nbsp;)&nbsp;</span><span id=Codehighlighter1_111_113_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_111_113_Open_Text><span style="COLOR: #000000">{&nbsp;}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_140_156_Open_Image onclick="this.style.display='none'; Codehighlighter1_140_156_Open_Text.style.display='none'; Codehighlighter1_140_156_Closed_Image.style.display='inline'; Codehighlighter1_140_156_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_140_156_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_140_156_Closed_Text.style.display='none'; Codehighlighter1_140_156_Open_Image.style.display='inline'; Codehighlighter1_140_156_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;()&nbsp;</span><span id=Codehighlighter1_140_156_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_140_156_Open_Text><span style="COLOR: #000000">{&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_obj;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 然后再使用func时，func( ref_wrapper&lt;CBaseObject&gt;( obj ) );这样，发生复制操作的最多就是这<br>个ref_wrapper，基本上也就是复制了一个指针，而不会复制整个obj。当然，这里可以写一个模板函数去<br>简化func的调用，如：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ref_wrapper</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">ref</span><span style="COLOR: #000000">(&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">t&nbsp;)<br><img id=Codehighlighter1_67_111_Open_Image onclick="this.style.display='none'; Codehighlighter1_67_111_Open_Text.style.display='none'; Codehighlighter1_67_111_Closed_Image.style.display='inline'; Codehighlighter1_67_111_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_67_111_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_67_111_Closed_Text.style.display='none'; Codehighlighter1_67_111_Open_Image.style.display='inline'; Codehighlighter1_67_111_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_67_111_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_67_111_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;ref_wrapper</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;t&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 这样调用的时候就简单了：func( ref( obj ) );<br>&nbsp;&nbsp;&nbsp; 其实这就是boost的ref库，按照其官方文档，ref库就是：<br>&nbsp;&nbsp;&nbsp; The Ref library is a small library that is useful for passing references to function <br>templates (algorithms) that would usually take copies of their arguments. </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 然后我就懵了。于是我不得不在kl_ref.h里写上check out boost::ref for more information的字眼。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 好，接下来说说第三次。<br>&nbsp;&nbsp;&nbsp; 第三次我遇到了这样一种需求，我需要一个容器，就像你知道的std::list。但是与std::list甚至STL<br>中所有容器都不同的是，这个容器里保存的东西具有不同的类型。<br>&nbsp;&nbsp;&nbsp; 这个时候我想起了tuple。我没有实现过tuple。大致上这个东西的实现原理就是利用类型递归来保存<br>数据，就像loki的type list。另一方面，tuple的尺寸似乎不能动态增长。<br>&nbsp;&nbsp;&nbsp; 于是我有了自己撇脚的实现：<br></font>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;base_type<br><img id=Codehighlighter1_24_63_Open_Image onclick="this.style.display='none'; Codehighlighter1_24_63_Open_Text.style.display='none'; Codehighlighter1_24_63_Closed_Image.style.display='inline'; Codehighlighter1_24_63_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_24_63_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_24_63_Closed_Text.style.display='none'; Codehighlighter1_24_63_Open_Image.style.display='inline'; Codehighlighter1_24_63_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_24_63_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_24_63_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_55_57_Open_Image onclick="this.style.display='none'; Codehighlighter1_55_57_Open_Text.style.display='none'; Codehighlighter1_55_57_Closed_Image.style.display='inline'; Codehighlighter1_55_57_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_55_57_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_55_57_Closed_Text.style.display='none'; Codehighlighter1_55_57_Open_Image.style.display='inline'; Codehighlighter1_55_57_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">base_type()&nbsp;</span><span id=Codehighlighter1_55_57_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_55_57_Open_Text><span style="COLOR: #000000">{&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;var_wrapper<br><img id=Codehighlighter1_120_257_Open_Image onclick="this.style.display='none'; Codehighlighter1_120_257_Open_Text.style.display='none'; Codehighlighter1_120_257_Closed_Image.style.display='inline'; Codehighlighter1_120_257_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_120_257_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_120_257_Closed_Text.style.display='none'; Codehighlighter1_120_257_Open_Image.style.display='inline'; Codehighlighter1_120_257_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_120_257_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_120_257_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_181_182_Open_Image onclick="this.style.display='none'; Codehighlighter1_181_182_Open_Text.style.display='none'; Codehighlighter1_181_182_Closed_Image.style.display='inline'; Codehighlighter1_181_182_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_181_182_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_181_182_Closed_Text.style.display='none'; Codehighlighter1_181_182_Open_Image.style.display='inline'; Codehighlighter1_181_182_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var_wrapper(&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">t&nbsp;)&nbsp;:&nbsp;_t(&nbsp;t&nbsp;)&nbsp;&nbsp;</span><span id=Codehighlighter1_181_182_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_181_182_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_209_222_Open_Image onclick="this.style.display='none'; Codehighlighter1_209_222_Open_Text.style.display='none'; Codehighlighter1_209_222_Closed_Image.style.display='inline'; Codehighlighter1_209_222_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_209_222_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_209_222_Closed_Text.style.display='none'; Codehighlighter1_209_222_Open_Image.style.display='inline'; Codehighlighter1_209_222_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;()&nbsp;</span><span id=Codehighlighter1_209_222_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_209_222_Open_Text><span style="COLOR: #000000">{&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;_t;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Tp&nbsp;_t;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;var_list<br><img id=Codehighlighter1_287_866_Open_Image onclick="this.style.display='none'; Codehighlighter1_287_866_Open_Text.style.display='none'; Codehighlighter1_287_866_Closed_Image.style.display='inline'; Codehighlighter1_287_866_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_287_866_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_287_866_Closed_Text.style.display='none'; Codehighlighter1_287_866_Open_Image.style.display='inline'; Codehighlighter1_287_866_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_287_866_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_287_866_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;std::vector</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">base_type</span><span style="COLOR: #000000">*&gt;</span><span style="COLOR: #000000">&nbsp;TypeList;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;add(&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">t&nbsp;)<br><img id=Codehighlighter1_448_555_Open_Image onclick="this.style.display='none'; Codehighlighter1_448_555_Open_Text.style.display='none'; Codehighlighter1_448_555_Closed_Image.style.display='inline'; Codehighlighter1_448_555_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_448_555_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_448_555_Closed_Text.style.display='none'; Codehighlighter1_448_555_Open_Image.style.display='inline'; Codehighlighter1_448_555_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_448_555_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_448_555_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var_wrapper</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">var&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;var_wrapper</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;t&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_list.push_back(&nbsp;t&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Tp&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000">(&nbsp;size_t&nbsp;index&nbsp;)<br><img id=Codehighlighter1_632_823_Open_Image onclick="this.style.display='none'; Codehighlighter1_632_823_Open_Text.style.display='none'; Codehighlighter1_632_823_Closed_Image.style.display='inline'; Codehighlighter1_632_823_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_632_823_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_632_823_Closed_Text.style.display='none'; Codehighlighter1_632_823_Open_Image.style.display='inline'; Codehighlighter1_632_823_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_632_823_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_632_823_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base_type&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">base</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;_list.at(&nbsp;index&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;var_wrapper</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;var_type;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var_type&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">var&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;static_cast</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">var_type</span><span style="COLOR: #000000">*&gt;</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">base</span><span style="COLOR: #000000">&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">var;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TypeList&nbsp;_list;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 说白了，我就是利用一个包装类将各种类型包装其中，然后利用基类指针实现统一管理。直白地说，我<br>对这个组件不满意。让人诟病的是，get接口是类型不安全的。例如：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;a;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CBaseObject&nbsp;obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;var_list&nbsp;my_var_list;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;my_var_list.add</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;a&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;my_var_list.add</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CBaseObject</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;obj&nbsp;);</span></div>
<p><br>&nbsp;&nbsp;&nbsp; 取出值的时候：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;b&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;my_var_list.</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CBaseObject&nbsp;cobj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;my_var_list.</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CBaseObject</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;);</span></div>
<p><br>&nbsp;&nbsp;&nbsp; 但是，因为get没有类型检查，即使你：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;CBaseObject&nbsp;cobj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;my_var_list.</span><span style="COLOR: #0000ff">get</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CBaseObject</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;);</span></div>
<p><br>&nbsp;&nbsp;&nbsp; 也不会出错，编译器不会给予你警告。<br>&nbsp;&nbsp;&nbsp; 事情到此结束，这个类型不安全的组件只能依靠程序员自己的谨慎去生存。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 然后，又是一个不小心，我在boost里看到了any。boost::any库同boost::ref库一样，是一个tiny <br>library。几十行的代码一目了然。<br>&nbsp;&nbsp;&nbsp; boost::any有一个placeholder基类，有一个template &lt;typename ValueType&gt; holder派生类，然后有<br>一个提供给外部的any类。看了代码后有一种让我喷血的感觉。其实现原理和我自己的完全一致。<br>&nbsp;&nbsp;&nbsp; 比较而言，我觉得我的var_list撇脚到了极致。因为我封装了容器，而这显然是没必要的，并且限制<br>了其使用范围。而boost::any则是仅仅封装了类型。<br>&nbsp;&nbsp;&nbsp; 数据转换方面，boost::any提供了any_cast和unsafe_any_cast。unsafe_any_cast和我这里用的转换<br>差不多，也就是我说的类型不安全。而他的any_cast呢？则是用到了typeid，多了次类型检查而已。<br>&nbsp;&nbsp;&nbsp; 没办法，看来var_list需要被删掉，直接搬boost::any过来吧，同样地check out boost::any for more<br>information...<br>&nbsp;&nbsp;&nbsp; 现在看来，boost真的很强大。我感觉再怎么偏门的需求，都能在boost里找到个实现。痛定思痛，决定<br>把boost doc长期开着。 </font>
<p><font size=2></font></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/64013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-10-15 11:23 <a href="http://www.cppblog.com/kevinlynx/archive/2008/10/15/64013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码自动生成-宏递归思想</title><link>http://www.cppblog.com/kevinlynx/archive/2008/08/20/59451.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 20 Aug 2008 09:48:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/08/20/59451.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/59451.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/08/20/59451.html#Feedback</comments><slash:comments>20</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/59451.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/59451.html</trackback:ping><description><![CDATA[<p><font size=2>Macro Recursion<br>author: Kevin Lynx </font>
<p><font size=2><strong>Preface </strong></font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 本文可能是&lt;<a href="http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html" target=_blank>代码自动生成-宏带来的奇技淫巧</a>&gt;的续写。我尽力阐述如何让宏递归（或者说重复）地有规律地产生一<br>些符号，而让我们少写很多重复代码，也许这些代码只有那么一点点的不同。将这项小技巧用于底层库的编写，会让代码<br>看起来干净不少，同时文件尺寸也会骤然下降。</font></p>
<font size=2>
<p><br><strong>Problem</strong></p>
<p><strong></strong><br>&nbsp;&nbsp;&nbsp; 如果你曾经写过<a href="http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html" target=_blank>functor</a>，那么你肯定对某些代码进行粘贴复制然后修改。更让人郁闷的是，这些代码基本是一样的。<br>例如，一个典型的functor可能为：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;Prototype</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;typename&nbsp;P1</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R(P1)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;typename&nbsp;P1,&nbsp;typename&nbsp;P2</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R(P1,P2)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; //好，接下去你可能厌烦了，可能会复制一个带有两个参数的functor，然后修改为处理3个参数的。<br>&nbsp;&nbsp;&nbsp; 这只是一个很简单的问题。宏不是c++里的东西，本文自然也不是讨论各种花哨的模板技术的。如果我之前那篇关于<br>宏的文章只是让你去分析问题以及更深层次地认识宏，那么现在我将分享我的这部分思想给你。<br>&nbsp;&nbsp;&nbsp; 关于上面的问题，我们期待得到这样的解决方案：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;DEF_PARAM(&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R(&nbsp;DEF_ARG(&nbsp;</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">&nbsp;)&nbsp;)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 那么，它将自动生成：<br></font><font size=2></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;typename&nbsp;P1,&nbsp;typename&nbsp;P2</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R(P1,P2)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 也就是说，DEF_PARAM(n)这个宏将根据n值自动生成一串符号，例如DEF_PARAM(2)就生成typename P1, typename P2。<br>同样，DEF_ARG(n)也会根据参数生成类似于P1,P2,...,Pn的符号串。 </font></p>
<p><font size=2><strong>思考</strong> </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 仔细思考下，我们可以看出DEF_PARAM和DEF_ARG这样的宏具有一种递归的特性（其实说成重复可能更合适）：每次展<br>开的内容基本一样，不断调用自身直到遇到终止条件。<br>&nbsp;&nbsp;&nbsp; 那么，我们的目标锁定于，用宏来实现递归。</font></p>
<p><font size=2><br><strong>Pre-Implement</strong> </font></p>
<p><font size=2>&nbsp;&nbsp;&nbsp; 在开始之前，我需要告诉你一些基本的东西：<br>&nbsp;&nbsp;&nbsp; 在阅读一个宏时，你最好按照预处理的处理方式去逐个展开。当我说到展开时，我的意思是把宏替换为宏体。预处理器<br>展开宏的过程大致为：如果宏参数也是个宏，那么先将宏参数全部展开，再展开该宏；这个时候会扫描展开后的宏，如果<br>遇到其他宏，则继续展开。例如有一下宏： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PI&nbsp;3.14</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;MUL_PI(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;PI</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TWO&nbsp;2</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 当我们写下MUL_PI( TWO )时，预处理发现MUL_PI的参数TWO 是个宏，那么先将TWO展开得到2，然后将2放进宏体展开<br>得到 2 * PI；预处理器对 2 * PI 进行扫描，发现还有宏PI，于是对PI做展开，得到 2 * 3.14。这个过程是递归的。<br>&nbsp;&nbsp;&nbsp; 但是也有例外，如果MUL_PI对宏参数进行了#或者##，那么该宏参数不会被展开。（参见以前那篇文章吧）<br>&nbsp;&nbsp;&nbsp; 任何时候，你可以通过以下宏去查看某个宏展开后的样子，可以方便你调试你的宏： </font>
<p><font size=2></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TO_STRING(&nbsp;x&nbsp;)&nbsp;TO_STRING1(&nbsp;x&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TO_STRING1(&nbsp;x&nbsp;)&nbsp;#x&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; （为什么要写个TO_STRING1，因为这是为了让x充分展开，避免上面提到的那个例外）&nbsp;&nbsp;&nbsp; </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 其他规则我会在文中需要的地方提出来。<br>实现 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 就像大部分介绍递归函数时候给的例子，这里我也将阶乘作为例子。考虑如下典型的阶乘函数：<br></font>
<p><font size=2></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fac(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;n&nbsp;)<br><img id=Codehighlighter1_25_95_Open_Image onclick="this.style.display='none'; Codehighlighter1_25_95_Open_Text.style.display='none'; Codehighlighter1_25_95_Closed_Image.style.display='inline'; Codehighlighter1_25_95_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_25_95_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_25_95_Closed_Text.style.display='none'; Codehighlighter1_25_95_Open_Image.style.display='inline'; Codehighlighter1_25_95_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_25_95_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_25_95_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;n&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;)&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;n&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;fac(&nbsp;n&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 其核心部分在于 n * fac( n - 1 )，我们假设我们的宏也可以写成这样的的形式：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;FAC(&nbsp;n&nbsp;-&nbsp;1&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 但是这样的宏是有问题的：<br>&nbsp;&nbsp;&nbsp; 当宏被展开时，如果遇到了自身，那么将被处理为一般符号，例如展开FAC( 3 )时，会遇到 FAC( 2 )，那么就把FAC<br>( 2 )中的FAC当成了一搬符号。<br>&nbsp;&nbsp;&nbsp; 这样的限制注定了我们无法让宏真正地调用自身来实现递归。于是，我们不得不写下以下丑陋的符号，从而去模拟递<br>归的每一次符号调用： </font>
<p><font size=2></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_1(&nbsp;n&nbsp;)&nbsp;1</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_2(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;FAC_##(n-1)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_3(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;FAC_##(n-1)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p><br>&nbsp;&nbsp;&nbsp; 这系列宏有点别扭（如果你足够细心），因为我们明显知道FAC_2返回的将是2，而FAC_3返回的当时6。我们这里只是<br>模拟，同样，这使得我们可以把FAC_1作为递归的终止条件。<br>&nbsp;&nbsp;&nbsp; 我们的预想是，当调用FAC_3时，它把n-1的值2合并到FAC_中，从而调用FAC_2，以此类推。<br>&nbsp;&nbsp;&nbsp; 但是这依然有问题，编译器会提示&#8216;找不到符号FAC_&#8217;。导致这个问题的原因在于：宏展开只是单纯的字符替换，是我们<br>想太多了，预处理器并不会去计算( n - 1 )的值是多少，也就是我们无法得到FAC_2这个宏。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 所以，FAC_3( 3 ) 会被初次替换为 3 * FAC_(3-1)( 3 - 1 )。这个时候编译器就把FAC_当成了一个普通符号。我们可以<br>自己定义个FAC_来证明这一点： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_(&nbsp;n&nbsp;)&nbsp;T&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 那么，FAC_3( 3 )就被替换为 3 * T(3-1)( 3 - 1 )。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 解决这个问题的办法关键在于，让预处理器自动计算出( n - 1 )。记住，我们解决问题的唯一办法是：字符替换。<br>所以，我们可以写下如下代码： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEC_1&nbsp;0</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEC_2&nbsp;1</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEC_3&nbsp;2&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;DEC_##n&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 通过，DEC( n )这个宏，我们可以获取到一个( n -1 )的数。例如，DEC( 3 )被替换为 DEC_3，继续替换为 2。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 于是，我们新的FAC系列宏变为： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_1(&nbsp;n&nbsp;)&nbsp;1</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_2(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;FAC_##DEC(&nbsp;n&nbsp;)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_3(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;FAC_##DEC(&nbsp;n&nbsp;)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 不好意思，这样依然是不正确的！预处理器直接把FAC_和DEC( n )连接成符号了，而不是单个地先处理他们，最后再<br>合并他们。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; OK，先解决这个问题：先处理FAC_和DEC( n )，再合并他们，而不是先合并他们。要解决这个问题，可以通过第三个宏<br>来实现： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;CHR(&nbsp;x,&nbsp;y&nbsp;)&nbsp;x##y&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 作为连接两个符号为一个符号的宏，这个宏显然是不正确的，因为宏展开还有个规则：如果宏体对宏参数使用了#或##，<br>那么宏参数不会被展开，也就是说：如果CHR( FAC_, DEC( 3 ) 那么得到的只会是 FAC_DEC( 3 )。通常情况下我们是<br>再写个宏： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;CHR(&nbsp;x,&nbsp;y&nbsp;)&nbsp;CHR1(&nbsp;x,&nbsp;y&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;CHR1(&nbsp;x,&nbsp;y&nbsp;)&nbsp;x##y&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 从而可以保证在正式连接x和y前，x和y都被完全展开。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 这个时候，我们的FAC系列宏变为： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_1(&nbsp;n&nbsp;)&nbsp;1</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_2(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;CHR(&nbsp;FAC_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_3(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;CHR(&nbsp;FAC_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;n&nbsp;-&nbsp;1&nbsp;)&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 结果呢？结果还是有问题。= =<br>&nbsp;&nbsp;&nbsp; 我们假设CHR( FAC_, DEC( n ) )已经真的按我们预想展开为 FAC_2了，那么FAC_3( 3 )会被展开为什么呢？<br>被展开为 3 * FAC_2( 3 - 1 )。这是错误的，传给 FAC_2 的参数是 3 - 1就意味着错误。我们又臆想预处理器会<br>帮我们计算 3 - 1的结果了。我们必须保证传给 FAC_2的参数是个数字2。解决这个问题的办法就是通过DEC(n)宏。 </font>
<p><font size=2>&nbsp;&nbsp; 于是，FAC系列宏变为： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_1(&nbsp;n&nbsp;)&nbsp;1</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_2(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;CHR(&nbsp;FAC_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;FAC_3(&nbsp;n&nbsp;)&nbsp;n&nbsp;*&nbsp;CHR(&nbsp;FAC_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 这个时候，FAC_3( 3 )将会被替换为：3*2*1。这就是我们要的结果。 </font>
<p><font size=2><strong>In practice</strong> </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 以上只是向你展示一个过程，用宏去计算阶乘，就像用模板去计算阶乘（模板元编程）一样，只是一个用于展示的东西，<br>没有什么实际价值。接下来我们开始有实际的工作，完成之前的预想： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;typename&nbsp;P1,&nbsp;typename&nbsp;P2,&nbsp;typename&nbsp;P3</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R&nbsp;(P1,&nbsp;P2,&nbsp;P3)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 直接: </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;R,&nbsp;PARAM(&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;functor</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">R&nbsp;(ARG(&nbsp;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">&nbsp;))</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 先考虑PARAM宏，该宏的任务就是生成类似于：typename P1, typename P2, typename P3这样的符号。我们假象它每一次<br>递归都生成 typename Pn, 的字符串，那么当他递归完时，可能就生成typename P1, typename P2, typename P3, 结果<br>多了个逗号，也许最后一次结果不该有逗号。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; ARG宏和PARAM宏本质上相同，只是重复的符号不是typename Pn，而是Pn。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 最直接想到的是： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_1(&nbsp;n&nbsp;)&nbsp;typename&nbsp;P##n</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_2(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)##,typename&nbsp;P##n</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_3(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)##,typename&nbsp;P##n&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 结果我们得到了个错误的展开结果：<br>typename PDEC( 2 ),typename PDEC( 3 ),typename P3 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 这个问题出在：PARAM_3( 3 )当替换为 PARAM_2( DEC( n ) )时，因为PARAM_2(n)宏对于宏参数n使用了##，也就是那个<br>typename P##n，所以这里不会把 DEC( n )展开，而是直接接到P后面。所以就成了typename PDEC( 3 )。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 为了消除这个问题，我们改进PARAM为： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;TYPE(&nbsp;n&nbsp;)&nbsp;,typename&nbsp;P##n</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_1(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;typename&nbsp;P,&nbsp;n&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_2(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;),&nbsp;TYPE(&nbsp;n&nbsp;)&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_3(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;),&nbsp;TYPE(&nbsp;n&nbsp;)&nbsp;)&nbsp;</span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 之所以加入TYPE(n)，是因为 ,typename P##n 这个宏本身存在逗号，将其直接用于宏体会出现问题。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 于是，我们得到了正确的结果。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 其实，PARAM系列宏宏体基本是一样的，除了终止条件那个宏，为什么我们要写这么多呢？理由在于宏体不能自己调用<br>自己，所以才有了PARAM_3, PARAM_2。 </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 我们可以将上面的一系列宏抽象化，使其具有可复用性： </font>
<p><font size=2>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM(&nbsp;n&nbsp;)&nbsp;,typename&nbsp;P##n</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_END&nbsp;typename&nbsp;P&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;ARG(&nbsp;n&nbsp;)&nbsp;,P##n</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;ARG_END&nbsp;P&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_1(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;typename&nbsp;P,&nbsp;n&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_2(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;),&nbsp;TYPE(&nbsp;n&nbsp;)&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;PARAM_3(&nbsp;n&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;PARAM_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;),&nbsp;TYPE(&nbsp;n&nbsp;)&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;REPEAT_1(&nbsp;n,&nbsp;f,&nbsp;e&nbsp;)&nbsp;CHR(&nbsp;e,&nbsp;n&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;REPEAT_2(&nbsp;n,&nbsp;f,&nbsp;e&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;REPEAT_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;),&nbsp;f,&nbsp;e&nbsp;),&nbsp;f(&nbsp;n&nbsp;)&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;REPEAT_3(&nbsp;n,&nbsp;f,&nbsp;e&nbsp;)&nbsp;CHR(&nbsp;CHR(&nbsp;REPEAT_,&nbsp;DEC(&nbsp;n&nbsp;)&nbsp;)(&nbsp;DEC(&nbsp;n&nbsp;),&nbsp;f,&nbsp;e&nbsp;),&nbsp;f(&nbsp;n&nbsp;)&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEF_PARAM(&nbsp;n&nbsp;)&nbsp;REPEAT_##n(&nbsp;n,&nbsp;PARAM,&nbsp;PARAM_END&nbsp;)</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;DEF_ARG(&nbsp;n&nbsp;)&nbsp;REPEAT_##n(&nbsp;n,&nbsp;ARG,&nbsp;ARG_END&nbsp;)&nbsp;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p></font>&nbsp;
<p><font size=2>&nbsp;&nbsp;&nbsp; 我们创建了可重用的REPEAT系列宏，用于创建诸如typename P1, typename P2, typename P3或者P1,P2,P3之类的符号，<br>通过更上层的DEF_PARAM(n)和DEF_ARG(n)，就可以直接创建出我们上面所需要的符号串，例如： </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; DEF_PARAM( 3 ) 就得到 typename P1, typename P2, typename P3<br>&nbsp;&nbsp;&nbsp; DEF_ARG( 3 ) 就得到 P1, P2, P3 </font>
<p><font size=2><strong>More in practice</strong> </font>
<p><font size=2>&nbsp;&nbsp;&nbsp; 下载中提供了我使用这个宏递归技术写的lua_binder(如果你看过&lt;<a href="http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html" target=_blank>实现自己的LUA绑定器-一个模板编程挑战</a> &gt;)，你<br>可以与上一个版本做一下比较，代码少了很多。<br>&nbsp;&nbsp;&nbsp; 同样，我希望你也能获取这种宏递归的思想。&nbsp;&nbsp;&nbsp; </font></p>
<p><font size=2><strong>相关下载</strong></font></p>
<p><font size=2>&nbsp;&nbsp; <a href="http://www.cppblog.com/Files/kevinlynx/mr_luabinder.zip" target=_blank>使用宏递归的lua_binder</a></font></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/59451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-08-20 17:48 <a href="http://www.cppblog.com/kevinlynx/archive/2008/08/20/59451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现自己的LUA绑定器-一个模板编程挑战</title><link>http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 13 Aug 2008 01:33:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/58684.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/58684.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/58684.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 实现LUA绑定器  author : Kevin Lynx  Preface &nbsp;&nbsp;&nbsp; 当LUA脚本调用我们注册的C函数时，我们需要逐个地从LUA栈里取出调用参数，当函数返回时，又需要一个一个地往LUA栈压入返回值，并且我们注册的函数只能是int()(lua_State*)类型。这很不方便，对于上层程序员来说更不方便。&nbsp;&nbsp;&nbsp; 因此我们要做的...&nbsp;&nbsp;<a href='http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html'>阅读全文</a><img src ="http://www.cppblog.com/kevinlynx/aggbug/58684.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-08-13 09:33 <a href="http://www.cppblog.com/kevinlynx/archive/2008/08/13/58684.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SGI STL的内存池</title><link>http://www.cppblog.com/kevinlynx/archive/2008/06/12/53054.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Thu, 12 Jun 2008 13:26:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/06/12/53054.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/53054.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/06/12/53054.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/53054.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/53054.html</trackback:ping><description><![CDATA[<p><font size=2>stl中各种容器都有一个可选的模板参数：allocator，也就是一个负责内存分配的组件。STL标准规定的allcator<br>被定义在memory文件中。STL标准规定的allocator只是单纯地封装operator new，效率上有点过意不去。 </font>
<p><font size=2>SGI实现的STL里，所有的容器都使用SGI自己定义的allocator。这个allocator实现了一个small object的内存池。<br>Loki里为了处理小对象的内存分配，也实现了类似的内存管理机制。 </font>
<p><font size=2>该内存池大致上，就是一大块一大块地从系统获取内存，然后将其分成很多小块以链表的形式链接起来。其内部<br>有很多不同类型的链表，不同的链表维护不同大小的内存块。每一次客户端要求分配内存时，allcator就根据请求<br>的大小找到相应的链表(最接近的尺寸)，然后从链表里取出内存。当客户端归还内存时，allocator就将这块内存<br>放回到对应的链表里。 </font>
<p><font size=2>我简单地画了幅图表示整个结构：</font>
<p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/SGISTL_12DE6/allocator.jpg"><img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=352 alt=allocator src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/SGISTL_12DE6/allocator_thumb.jpg" width=434 border=0></a>
<p><font size=2>allocator内部维护一个链表数组，数组元素全部是链表头指针。链表A每一个节点维护一个8bytes的内存块，链表<br>B每一个节点维护一个16bytes的内存块。 </font>
<p><font size=2>当客户端请求分配10bytes的内存时，allocator将10调整为最接近的16bytes(只能大于10bytes)，然后发现16bytes<br>这个链表(链表B)里有可用内存块，于是从B里取出一块内存返回。当客户端归还时，allocator找到对应的链表，将<br>内存重新放回链表B即可。 </font>
<p><font size=2>大致过程就这么简单，也许有人要说用链表维护一块内存，链表本身就会浪费一些内存(在我很早前接触内存池时，<br>总会看到类似的论点= =|)，其实通过一些简单的技巧是完全可以避免的。例如，这里allocator维护了很多内存块，<br>反正这些内存本身就是闲置的，因此我们就可以直接在这些内存里记录链表的信息(下一个元素)。 </font>
<p><font size=2>还是写点代码详细说下这个小技巧：</font>
<p>&nbsp;&nbsp;&nbsp; </p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Obj<br><img id=Codehighlighter1_15_40_Open_Image onclick="this.style.display='none'; Codehighlighter1_15_40_Open_Text.style.display='none'; Codehighlighter1_15_40_Closed_Image.style.display='inline'; Codehighlighter1_15_40_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_15_40_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_15_40_Closed_Text.style.display='none'; Codehighlighter1_15_40_Open_Image.style.display='inline'; Codehighlighter1_15_40_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_15_40_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_15_40_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Obj&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">next;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">mem&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;malloc(&nbsp;</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Obj&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">header&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(Obj</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)&nbsp;mem;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Obj&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">cur_obj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;header;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Obj&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">next_obj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;cur_obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;;&nbsp;</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">&nbsp;i&nbsp;)<br><img id=Codehighlighter1_195_441_Open_Image onclick="this.style.display='none'; Codehighlighter1_195_441_Open_Text.style.display='none'; Codehighlighter1_195_441_Closed_Image.style.display='inline'; Codehighlighter1_195_441_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_195_441_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_195_441_Closed_Text.style.display='none'; Codehighlighter1_195_441_Open_Image.style.display='inline'; Codehighlighter1_195_441_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_195_441_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_195_441_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur_obj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;next_obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next_obj&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(Obj</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)((</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)next_obj&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;i&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">9</span><span style="COLOR: #000000">&nbsp;)<br><img id=Codehighlighter1_304_364_Open_Image onclick="this.style.display='none'; Codehighlighter1_304_364_Open_Text.style.display='none'; Codehighlighter1_304_364_Closed_Image.style.display='inline'; Codehighlighter1_304_364_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_304_364_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_304_364_Closed_Text.style.display='none'; Codehighlighter1_304_364_Open_Image.style.display='inline'; Codehighlighter1_304_364_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_304_364_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_304_364_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur_obj</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">next&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_387_435_Open_Image onclick="this.style.display='none'; Codehighlighter1_387_435_Open_Text.style.display='none'; Codehighlighter1_387_435_Closed_Image.style.display='inline'; Codehighlighter1_387_435_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_387_435_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_387_435_Closed_Text.style.display='none'; Codehighlighter1_387_435_Open_Image.style.display='inline'; Codehighlighter1_387_435_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_387_435_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_387_435_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur_obj</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">next&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;next_obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;free(&nbsp;mem&nbsp;);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;
<p><font size=2>这样，通过header指针和next域，就可以逐块(这里是10byts)地访问mem所指向的内存，而这些链表的节点，都<br>是直接保存在这块内存里的，所以完全没有额外消耗。 </font>
<p><font size=2>我用C模仿着SGI的这个allocator写了个可配置的内存池，在其上按照STL的标准包装了一个allocator，可以直接<br>用于VC自带的STL里。</font><a href="http://www.cppblog.com/Files/kevinlynx/alloc.rar" target=_blank><font size=2>测试代码</font></a><font size=2>稍微测试了下，发现在不同的机器上有明显的差距。 </font></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/53054.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-06-12 21:26 <a href="http://www.cppblog.com/kevinlynx/archive/2008/06/12/53054.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程下vc2003,vc2005对虚函数表处理的BUG？</title><link>http://www.cppblog.com/kevinlynx/archive/2008/04/24/48001.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Thu, 24 Apr 2008 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/04/24/48001.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/48001.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/04/24/48001.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/48001.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/48001.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 考虑一下多线程代码，在设计上，App为了获取更多的功能，从Window派生，而App同时为了获取某个模块的回调(所谓的Listener)，App同时派生Listener，并将自己的指针交给另一个模块，另一个模块通过该指针多态回调到App的实现(对Listener规定的接口的implemention)。设计上只是一个很简单的Listener回调，在单线程模式下一切都很正常(后面我会罗列代码)，但是换...&nbsp;&nbsp;<a href='http://www.cppblog.com/kevinlynx/archive/2008/04/24/48001.html'>阅读全文</a><img src ="http://www.cppblog.com/kevinlynx/aggbug/48001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-04-24 14:40 <a href="http://www.cppblog.com/kevinlynx/archive/2008/04/24/48001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试经验总结-VC下的错误对话框(陆续更新6.12.2008)</title><link>http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Thu, 24 Apr 2008 05:43:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/47998.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/47998.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/47998.html</trackback:ping><description><![CDATA[<p><font size="2">很早前就想写点总结将编程中遇到的各种错误刨根挖底地罗列出来。但是因为这些错误（VC中开调试器遇到的各种错误对话框）都是随机性的，真正想总结的时候又不想不起来有哪些错误。恰好最近运气比较背，各种错误都被我遇遍了，于是恰好有机会做个总结。 </font> <p><font size="2">这里所说的VC下的错误对话框时指在VC中开调试器运行程序时，IDE弹出的对话框。</font>  <p><strong>1.不是错误的错误：断言</strong> .</p> <p>将断言视为错误其实有点可笑，但是因为有些同学甚至不知道这个，所以我稍微提一下。断言对话框大致上类似于：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/assert_1.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="257" alt="assert" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/assert_thumb_1.jpg" width="444" border="0"></a> </p> <p>断言对话框是由assert引起的，在对话框上通常会给出表达式，例如assert( 0 ); 弹出对话框时就会将0这个表达式显示出来（Expression:0)。关于assert的具体信息建议自己google。这里稍微提一下一个技巧：有时候为了让assert提供更多的信息，我们可以这样写一个assert:</p> <p>assert( expression &amp;&amp; "Function : invalid argument!" ); </p> <p>因为字符串被用在布尔表达式中时，始终为true，不会妨碍对expression的判断，当断言发生时(expression为false) 时，断言对话框上就会显示这个字符串，从而方便我们调试。</p> <p>要解决这个问题，首先要确定断言发生的位置，如果是你自己设置的断言被引发，就很好解决，如果是系统内部的函数产生的，那么一般是因为你传入的函数参数无效引起。</p> <p>&nbsp;</p> <p><strong>2.内存相关：最简单的非法访问：</strong></p> <p>C、C++程序中经常误用无效的指针，从而大致各种各样的非法内存访问（写/读）。最简单的情况类似于：</p> <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/wrongaccess.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="186" alt="wrongaccess" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/wrongaccess_thumb.jpg" width="444" border="0"></a> </p> <p>这样的情况由类似以下代码引起：</p> <p>char *p = 0;  <p>*p = 'a';  <p>当你看到类似于“写入位置XXXX时发生访问冲突“时，那么你大致可以断定，你的程序在某个地方访问到非法内存。开调试器对调用堆栈进行跟踪即可找出错误。</p> <p>&nbsp;</p> <p><strong>3.内存相关：不小心的栈上数组越界：</strong></p> <p>当你写下类似以下的代码时：</p> <p>char str[3];  <p>strcpy( str, "abc" );  <p>就将看到如下的对话框：  <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/stackerror.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="235" alt="stackerror" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/stackerror_thumb.jpg" width="516" border="0"></a>&nbsp; <p>对话框大致的意思就是说str周围的栈被破坏了，因为str本身就被放在栈上，所以strcpy(str,"abc")多写入的'\0'就写到非法的栈区域。看到这样的对话框可以根据调用堆栈定位到错误发生的函数，然后检查此函数内部定义的数组访问，即可解决问题。  <p>&nbsp; <p><strong>4.内存相关：不小心的堆上数组越界：<br></strong>并不是每次数组越界都会得到上面所描述的错误，当数组是在堆上分配时，情况就变得隐秘得多：  <p>char *str = new char [2];  <p>strcpy( str, "ab" ); //执行到这里时并不见得会崩溃  <p>delete [] str;//但是到这里时就肯定会崩溃  <p>以上代码导致的错误对话框还要诡异些：  <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/heaperror.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="206" alt="heaperror" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/heaperror_thumb.jpg" width="516" border="0"></a>  <p>似乎不同的DAMAGE对应的错误号（这里是47）都不一样，因为这里的错误发生在delete，而delete跟new很可能在不同的地方，所以这个错误调试起来不是那么容易，很多时候只能靠经验。  <p>当看到类似的对话框时，根据调用堆栈跟到delete时，你就可以大致怀疑堆上数组越界。  <p>&nbsp; <p><strong>5.调用相关：函数调用约定带来的错误：</strong>  <p>这是所有我这里描述的错误中最诡异的一种，先看下对话框大致的样子：  <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/run_functioncall2.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="195" alt="run_functioncall2" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/run_functioncall2_thumb.jpg" width="446" border="0"></a>  <p>对话框大致的意思就是说（没开调试器时对话框样式可能不一样），通过函数指针调用某个函数时，函数指针的类型（函数原型）可能与函数指针指向的函数的类型不一样。这里的类型不一致主要是调用约定(call conversation）不一样。如果函数类型（参数个数，返回值）不一样，一般不会出错。  <p>调用约定是指调用一个函数时，函数参数的压入顺序、谁来清理栈的内容等。例如默认的C、C++调用约定__cdecl，对于函数的参数是从右往左压入。而__stdcall（WIN API的调用约定）则是从左向右压。我这里所说的函数类型不一样，就是指一个函数是使用__cdecl，还是__stdcall。例如以下代码：  <p>&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #000000">#include </span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff">void</span><span style="color: #000000"> __stdcall show( </span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">str ) <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img id="Codehighlighter1_63_67_Open_Image" onclick="this.style.display='none'; Codehighlighter1_63_67_Open_Text.style.display='none'; Codehighlighter1_63_67_Closed_Image.style.display='inline'; Codehighlighter1_63_67_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_63_67_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_63_67_Closed_Text.style.display='none'; Codehighlighter1_63_67_Open_Image.style.display='inline'; Codehighlighter1_63_67_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_63_67_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_63_67_Open_Text"><span style="color: #000000">{ <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff">void</span><span style="color: #000000"> __stdcall show2() <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img id="Codehighlighter1_96_100_Open_Image" onclick="this.style.display='none'; Codehighlighter1_96_100_Open_Text.style.display='none'; Codehighlighter1_96_100_Closed_Image.style.display='inline'; Codehighlighter1_96_100_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_96_100_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_96_100_Closed_Text.style.display='none'; Codehighlighter1_96_100_Open_Image.style.display='inline'; Codehighlighter1_96_100_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_96_100_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_96_100_Open_Text"><span style="color: #000000">{ <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span><span style="color: #0000ff">int</span><span style="color: #000000"> main() <br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img id="Codehighlighter1_117_239_Open_Image" onclick="this.style.display='none'; Codehighlighter1_117_239_Open_Text.style.display='none'; Codehighlighter1_117_239_Closed_Image.style.display='inline'; Codehighlighter1_117_239_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_117_239_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_117_239_Closed_Text.style.display='none'; Codehighlighter1_117_239_Open_Image.style.display='inline'; Codehighlighter1_117_239_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_117_239_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_117_239_Open_Text"><span style="color: #000000">{ <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">typedef </span><span style="color: #0000ff">void</span><span style="color: #000000"> (</span><span style="color: #000000">*</span><span style="color: #000000">Func)( </span><span style="color: #0000ff">const</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">); <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">p </span><span style="color: #000000">=</span><span style="color: #000000"> show; <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">Func my_func </span><span style="color: #000000">=</span><span style="color: #000000"> (Func) p; <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">my_func( </span><span style="color: #000000">"</span><span style="color: #000000">kevin</span><span style="color: #000000">"</span><span style="color: #000000"> ); <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"></span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">; <br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div> <p>&nbsp;</p> <p>因为Func默认地被处理为__cdecl，而show是__stdcall的，所以当通过函数指针my_func时，就导致了以上对话框的出现。但是当p指向show2时，又不会出错，这是因为show2没有参数，不同的调用约定不影响这个规则。<br><br></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><strong style="mso-bidi-font-weight: normal"><span lang="EN-US">6.</span></strong><strong style="mso-bidi-font-weight: normal"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">异常相关：默认终止程序</span><span lang="EN-US"><o:p></o:p></span></strong></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当我们使用</span><span lang="EN-US">C++</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">库时，因为库本身可能会抛出</span><span lang="EN-US">C++</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">异常，如果你不捕获这个异常，那么</span><span lang="EN-US">C++</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">默认就会调用</span><span lang="EN-US">abort</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（或者</span><span lang="EN-US">exit</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）函数终止程序。例如：</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span lang="EN-US"><o:p>&nbsp;</p> <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"><span style="color: #0000ff">void</span><span style="color: #000000"> test()<br><img id="Codehighlighter1_12_61_Open_Image" onclick="this.style.display='none'; Codehighlighter1_12_61_Open_Text.style.display='none'; Codehighlighter1_12_61_Closed_Image.style.display='inline'; Codehighlighter1_12_61_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_12_61_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_12_61_Closed_Text.style.display='none'; Codehighlighter1_12_61_Open_Image.style.display='inline'; Codehighlighter1_12_61_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span id="Codehighlighter1_12_61_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id="Codehighlighter1_12_61_Open_Text"><span style="color: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">throw</span><span style="color: #000000"> std::exception( </span><span style="color: #000000">"</span><span style="color: #000000">some exceptions</span><span style="color: #000000">"</span><span style="color: #000000"> );<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align="top"></span></div> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"></o:p></span>&nbsp;</p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当你调用</span><span lang="EN-US">test</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数时，如果不</span><span lang="EN-US">catch</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这个异常，开调试器就会得到类似的错误对话框：</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span lang="EN-US"><o:p><img height="199" alt="" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/exception.jpg" width="443" border="0">&nbsp;</o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">而如果不开调试器，则会得到：</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span lang="EN-US"><o:p>&nbsp;<img height="232" alt="" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/abort.jpg" width="439" border="0"></o:p></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当你看到类似于“</span><span lang="EN-US">This application has requested the Runtime to terminate it…”</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">之类的字眼时，那就表明程序调用了</span><span lang="EN-US">abort</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">（或</span><span lang="EN-US">exit</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）函数，导致程序异常终止。其实这个错误只要开调试器，一般可以准确定位错误的发生点。</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p> <p><strong>7.VC运行时检查-未初始化变量</strong></p> <p>VC的调试器会对代码进行运行时检查，这可能会导致VC弹出对你看上去正确的代码。这也许不是一个错误。例如：</p> <p>int test_var;  <p>if( test_var == -1 )<br>{<br>&nbsp;&nbsp;&nbsp; test_var = 0;<br>}  <p>test_var没有初始化就进行if判断，当运行以上代码开调试器时，就会得到如下对话框：  <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/withoutinit.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="192" alt="withoutinit" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/withoutinit_thumb.jpg" width="442" border="0"></a> <p><strong>8.破坏的堆</strong> <p>VC对于在堆上分配的内存都做了记录，我想这主要用于free释放内存时做归还处理。 <p>char *p = (char*) malloc( 100 );<br>p += 10;<br>free( p ); <p>当执行以上代码时，因为p的值已经改变，提交到free的指针值变化，VC就会给出以下错误提示： <p><a href="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/bad_heap.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="190" alt="bad_heap" src="http://www.cppblog.com/images/cppblog_com/kevinlynx/WindowsLiveWriter/VC_BA3E/bad_heap_thumb.jpg" width="443" border="0"></a></p><img src ="http://www.cppblog.com/kevinlynx/aggbug/47998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-04-24 13:43 <a href="http://www.cppblog.com/kevinlynx/archive/2008/04/24/47998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码自动生成-宏带来的奇技淫巧</title><link>http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 19 Mar 2008 02:34:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/44828.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/44828.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/44828.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt">Author : Kevin Lynx</p>
<p style="FONT-SIZE: 10pt">众多C++书籍都忠告我们C语言宏是万恶之首，但事情总不如我们想象的那么坏，就如同goto一样。宏有<br>一个很大的作用，就是自动为我们产生代码。如果说模板可以为我们产生各种型别的代码(型别替换)，<br>那么宏其实可以为我们在符号上产生新的代码(即符号替换、增加)。</p>
<p style="FONT-SIZE: 10pt">关于宏的一些语法问题，可以在google上找到。相信我，你对于宏的了解绝对没你想象的那么多。如果你<br>还不知道#和##，也不知道prescan，那么你肯定对宏的了解不够。</p>
<p style="FONT-SIZE: 10pt">我稍微讲解下宏的一些语法问题(说语法问题似乎不妥，macro只与preprocessor有关，跟语义分析又无关)：</p>
<p style="FONT-SIZE: 10pt">1. 宏可以像函数一样被定义，例如：<br>&nbsp;&nbsp; #define min(x,y) (x&lt;y?x:y) //事实上这个宏存在BUG<br>&nbsp;&nbsp; 但是在实际使用时，只有当写上min()，必须加括号，min才会被作为宏展开，否则不做任何处理。<br>&nbsp;&nbsp; <br>2. 如果宏需要参数，你可以不传，编译器会给你警告(宏参数不够)，但是这会导致错误。如C++书籍中所描<br>&nbsp;&nbsp; 述的，编译器(预处理器)对宏的语法检查不够，所以更多的检查性工作得你自己来做。</p>
<p style="FONT-SIZE: 10pt">3. 很多程序员不知道的#和##<br>&nbsp;&nbsp; #符号把一个符号直接转换为字符串，例如：<br>&nbsp;&nbsp; #define STRING(x) #x<br>&nbsp;&nbsp; const char *str = STRING( test_string ); str的内容就是"test_string"，也就是说#会把其后的符号<br>&nbsp;&nbsp; 直接加上双引号。<br>&nbsp;&nbsp; ##符号会连接两个符号，从而产生新的符号(词法层次)，例如：<br>&nbsp;&nbsp; #define SIGN( x ) INT_##x<br>&nbsp;&nbsp; int SIGN( 1 ); 宏被展开后将成为：int INT_1; </p>
<p style="FONT-SIZE: 10pt">4. 变参宏，这个比较酷，它使得你可以定义类似的宏：<br>&nbsp;&nbsp; #define LOG( format, ... ) printf( format, __VA_ARGS__ )<br>&nbsp;&nbsp; LOG( "%s %d", str, count );<br>&nbsp;&nbsp; __VA_ARGS__是系统预定义宏，被自动替换为参数列表。</p>
<p style="FONT-SIZE: 10pt">5. 当一个宏自己调用自己时，会发生什么？例如：<br>&nbsp;&nbsp; #define TEST( x ) ( x + TEST( x ) )<br>&nbsp;&nbsp; TEST( 1 ); 会发生什么？为了防止无限制递归展开，语法规定，当一个宏遇到自己时，就停止展开，也就是<br>&nbsp;&nbsp; 说，当对TEST( 1 )进行展开时，展开过程中又发现了一个TEST，那么就将这个TEST当作一般的符号。TEST(1)<br>&nbsp;&nbsp; 最终被展开为：1 + TEST( 1) 。</p>
<p style="FONT-SIZE: 10pt">6. 宏参数的prescan，<br>&nbsp;&nbsp; 当一个宏参数被放进宏体时，这个宏参数会首先被全部展开(有例外，见下文)。当展开后的宏参数被放进宏体时，<br>&nbsp;&nbsp; 预处理器对新展开的宏体进行第二次扫描，并继续展开。例如：<br>&nbsp;&nbsp; #define PARAM( x ) x<br>&nbsp;&nbsp; #define ADDPARAM( x ) INT_##x<br>&nbsp;&nbsp; PARAM( ADDPARAM( 1 ) ); <br>&nbsp;&nbsp; 因为ADDPARAM( 1 ) 是作为PARAM的宏参数，所以先将ADDPARAM( 1 )展开为INT_1，然后再将INT_1放进PARAM。<br>&nbsp;&nbsp; <br>&nbsp;&nbsp; 例外情况是，如果PARAM宏里对宏参数使用了#或##，那么宏参数不会被展开：<br>&nbsp;&nbsp; #define PARAM( x ) #x<br>&nbsp;&nbsp; #define ADDPARAM( x ) INT_##x<br>&nbsp;&nbsp; PARAM( ADDPARAM( 1 ) ); 将被展开为"ADDPARAM( 1 )"。</p>
<p style="FONT-SIZE: 10pt">&nbsp;&nbsp; 使用这么一个规则，可以创建一个很有趣的技术：打印出一个宏被展开后的样子，这样可以方便你分析代码：<br>&nbsp;&nbsp; #define TO_STRING( x ) TO_STRING1( x )<br>&nbsp;&nbsp; #define TO_STRING1( x ) #x<br>&nbsp;&nbsp; TO_STRING首先会将x全部展开(如果x也是一个宏的话)，然后再传给TO_STRING1转换为字符串，现在你可以这样：<br>&nbsp;&nbsp; const char *str = TO_STRING( PARAM( ADDPARAM( 1 ) ) );去一探PARAM展开后的样子。</p>
<p style="FONT-SIZE: 10pt">7. 一个很重要的补充：就像我在第一点说的那样，如果一个像函数的宏在使用时没有出现括号，那么预处理器只是<br>&nbsp;&nbsp; 将这个宏作为一般的符号处理(那就是不处理)。</p>
<p style="FONT-SIZE: 10pt"><br>我们来见识一下宏是如何帮助我们自动产生代码的。如我所说，宏是在符号层次产生代码。我在分析Boost.Function<br>模块时，因为它使用了大量的宏(宏嵌套，再嵌套)，导致我压根没看明白代码。后来发现了一个小型的模板库ttl，说的<br>是开发一些小型组件去取代部分Boost(这是一个好理由，因为Boost确实太大)。同样，这个库也包含了一个function库。<br>这里的function也就是我之前提到的functor。ttl.function库里为了自动产生很多类似的代码，使用了一个宏：</p>
<p style="FONT-SIZE: 10pt">#define TTL_FUNC_BUILD_FUNCTOR_CALLER(n)&nbsp; \<br>&nbsp;template&lt; typename R, TTL_TPARAMS(n) &gt; \<br>&nbsp;struct functor_caller_base##n \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ///...<br>该宏的最终目的是：通过类似于TTL_FUNC_BUILD_FUNCTOR_CALLER(1)的调用方式，自动产生很多functor_caller_base模板：<br>template &lt;typename R, typename T1&gt; struct functor_caller_base1<br>template &lt;typename R, typename T1, typename T2&gt; struct functor_caller_base2<br>template &lt;typename R, typename T1, typename T2, typename T3&gt; struct functor_caller_base3<br>///... <br>那么，核心部分在于TTL_TPARAMS(n)这个宏，可以看出这个宏最终产生的是：<br>typename T1<br>typename T1, typename T2<br>typename T1, typename T2, typename T3<br>///...<br>我们不妨分析TTL_TPARAMS(n)的整个过程。分析宏主要把握我以上提到的一些要点即可。以下过程我建议你翻着ttl的代码，<br>相关代码文件：function.hpp, macro_params.hpp, macro_repeat.hpp, macro_misc.hpp, macro_counter.hpp。</p>
<p style="FONT-SIZE: 10pt">so, here we go </p>
<p style="FONT-SIZE: 10pt">分析过程，逐层分析，逐层展开，例如TTL_TPARAMS(1)：</p>
<p style="FONT-SIZE: 10pt">#define TTL_TPARAMS(n) TTL_TPARAMSX(n,T)&nbsp; <br>=&gt; TTL_TPARAMSX( 1, T )<br>#define TTL_TPARAMSX(n,t) TTL_REPEAT(n, TTL_TPARAM, TTL_TPARAM_END, t)<br>=&gt; TTL_REPEAT( 1, TTL_TPARAM, TTL_TPARAM_END, T )<br>#define TTL_TPARAM(n,t) typename t##n, <br>#define TTL_TPARAM_END(n,t) typename t##n<br>#define TTL_REPEAT(n, m, l, p) TTL_APPEND(TTL_REPEAT_, TTL_DEC(n))(m,l,p) TTL_APPEND(TTL_LAST_REPEAT_,n)(l,p)<br>注意，TTL_TPARAM, TTL_TPARAM_END虽然也是两个宏，他们被作为TTL_REPEAT宏的参数，按照prescan规则，似乎应该先将<br>这两个宏展开再传给TTL_REPEAT。但是，如同我在前面重点提到的，这两个宏是function-like macro，使用时需要加括号，<br>如果没加括号，则不当作宏处理。因此，展开TTL_REPEAT时，应该为：<br>=&gt; TTL_APPEND( TTL_REPEAT_, TTL_DEC(1))(TTL_TPARAM,TTL_TPARAM_END,T) TTL_APPEND( TTL_LAST_REPEAT_,1)(<br>TTL_TPARAM_END,T)<br>这个宏体看起来很复杂，仔细分析下，可以分为两部分：<br>TTL_APPEND( TTL_REPEAT_, TTL_DEC(1))(TTL_TPARAM,TTL_TPARAM_END,T)以及<br>TTL_APPEND( TTL_LAST_REPEAT_,1)(TTL_TPARAM_END,T)<br>先分析第一部分：<br>#define TTL_APPEND( x, y ) TTL_APPEND1(x,y) //先展开x,y再将x,y连接起来<br>#define TTL_APPEND1( x, y ) x ## y<br>#define TTL_DEC(n) TTL_APPEND(TTL_CNTDEC_, n)<br>根据先展开参数的原则，会先展开TTL_DEC(1)<br>=&gt; TTL_APPEND(TTL_CNTDEC_,1) =&gt; TTL_CNTDEC_1 <br>#define TTL_CNTDEC_1 0&nbsp; 注意，TTL_CNTDEC_不是宏，TTL_CNTDEC_1是一个宏。<br>=&gt; 0 ， 也就是说，TTL_DEC(1)最终被展开为0。回到TTL_APPEND部分：<br>=&gt; TTL_REPEAT_0 (TTL_TPARAM,TTL_TPARAM_END,T) <br>#define TTL_REPEAT_0(m,l,p)<br>TTL_REPEAT_0这个宏为空，那么，上面说的第一部分被忽略，现在只剩下第二部分：<br>TTL_APPEND( TTL_LAST_REPEAT_,1)(TTL_TPARAM_END,T)<br>=&gt; TTL_LAST_REPEAT_1 (TTL_TPARAM_END,T) // TTL_APPEND将TTL_LAST_REPEAT_和1合并起来<br>#define TTL_LAST_REPEAT_1(m,p) m(1,p)<br>=&gt; TTL_TPARAM_END( 1, T )<br>#define TTL_TPARAM_END(n,t) typename t##n<br>=&gt; typename T1&nbsp; 展开完毕。</p>
<p style="FONT-SIZE: 10pt">虽然我们分析出来了，但是这其实并不是我们想要的。我们应该从那些宏里去获取作者关于宏的编程思想。很好地使用宏<br>看上去似乎是一些偏门的奇技淫巧，但是他确实可以让我们编码更自动化。</p>
<p style="FONT-SIZE: 10pt">参考资料：<br>macro语法: http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Macros.html<br>ttl(tiny template library) : <a href="http://tinytl.sourceforge.net/">http://tinytl.sourceforge.net/</a></p>
<p style="FONT-SIZE: 10pt">&nbsp;&nbsp; <br>&nbsp;</p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/44828.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-03-19 10:34 <a href="http://www.cppblog.com/kevinlynx/archive/2008/03/19/44828.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现functor - 增强型的函数指针</title><link>http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Mon, 17 Mar 2008 03:13:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/44678.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html#Feedback</comments><slash:comments>14</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/44678.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/44678.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 作者：Kevin Lynx需求：开发一种组件，用以包装C函数、通常的函数对象、成员函数，使其对外保持一种一致的接口。我将最终的组件称为functor，这里的functor与loki中的functor以及boost中的function功能一致，同STL中的functor在概念层次上可以说也是一样的。那么，functor其实也可以进一步传进其他functor构成新的functor。C++世...&nbsp;&nbsp;<a href='http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html'>阅读全文</a><img src ="http://www.cppblog.com/kevinlynx/aggbug/44678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-03-17 11:13 <a href="http://www.cppblog.com/kevinlynx/archive/2008/03/17/44678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分析stl function objects模块</title><link>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44362.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Thu, 13 Mar 2008 05:31:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44362.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/44362.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44362.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/44362.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/44362.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt"><br>从SGI的STl文档来看，STL functor(function object)模块主要分为两个部分：预先定义的functor<br>以及functor adaptors。除此之外，为了使客端程序员写出适用于functor adaptor的functor，STL<br>又定义了一系列基本上只包含typedef的空类型(例如unary_function)。用户只需要派生这些类，即<br>可让自己写的functor被functor adaptor使用。以下称类基类型为base functor。</p>
<p style="FONT-SIZE: 10pt">base functor包括: unary_function, binary_function,分别表示只有一个参数的函数和有两个参数<br>的函数。实际上STL里还有一个所谓的generator，代表没有参数的函数。因为STL泛型算法一般最多<br>只会使用两个参数的函数，所以这里并没有定义更多参数的base functor。</p>
<p style="FONT-SIZE: 10pt">可被functor adaptor使用的functor又称为adaptable function，根据参数的个数，会被命名为诸如<br>adaptable unary function, adaptable binary function。</p>
<p style="FONT-SIZE: 10pt">一个返回值为bool的functor又被称为predicate，可被用于functor adaptor的predicate被称为<br>adaptable predicate。其实所谓的adaptable，只需要在类型内部typedef一些类型即可，一般包括<br>first_argument_type, second_argument_type, result_type。functor adaptor会使用这些定义。</p>
<p style="FONT-SIZE: 10pt">预定义的functors都是些很简单的functor，基本上就是封装诸如plus, minus, equal_to之类的算术<br>运算，列举一个predefined functor的代码：<br>&nbsp; </p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;plus&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;binary_function</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp,&nbsp;_Tp,&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_77_189_Open_Image onclick="this.style.display='none'; Codehighlighter1_77_189_Open_Text.style.display='none'; Codehighlighter1_77_189_Closed_Image.style.display='inline'; Codehighlighter1_77_189_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_77_189_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_77_189_Closed_Text.style.display='none'; Codehighlighter1_77_189_Open_Image.style.display='inline'; Codehighlighter1_77_189_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_77_189_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_77_189_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Tp&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">()(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__y)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br><img id=Codehighlighter1_145_181_Open_Image onclick="this.style.display='none'; Codehighlighter1_145_181_Open_Text.style.display='none'; Codehighlighter1_145_181_Closed_Image.style.display='inline'; Codehighlighter1_145_181_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_145_181_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_145_181_Closed_Text.style.display='none'; Codehighlighter1_145_181_Open_Image.style.display='inline'; Codehighlighter1_145_181_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_145_181_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_145_181_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;__x&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;__y;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;</span></div>
<p style="FONT-SIZE: 10pt"><br>因为从binary_function(即我所谓的base functor)派生，因此这些predefined functor也是adaptable <br>function。</p>
<p style="FONT-SIZE: 10pt">functor adaptors里有很多有趣的东西，其实functor adaptor也是一些functor(从SGI的观点来看，一般<br>的C函数，函数指针都算作functor)。所不同的是，他们通常会适配(adapt)一种functor到另一种。例如：<br>std::binder1st，严格地说它是一个函数模板，它会把一个adaptable binary function转换为一个<br>adaptable unary function，并绑定一个参数。又如: std::ptr_fun，它会将一个只有一个参数的C函数<br>适配成一个pointer_to_unary_function的functor。</p>
<p style="FONT-SIZE: 10pt">下面列举一些具体的代码：<br>关于base functor，基本上就只有unary_function, binary_function :<br>&nbsp; </p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Arg,&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Result</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;unary_function<br><img id=Codehighlighter1_63_157_Open_Image onclick="this.style.display='none'; Codehighlighter1_63_157_Open_Text.style.display='none'; Codehighlighter1_63_157_Closed_Image.style.display='inline'; Codehighlighter1_63_157_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_63_157_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_63_157_Closed_Text.style.display='none'; Codehighlighter1_63_157_Open_Image.style.display='inline'; Codehighlighter1_63_157_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_63_157_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_63_157_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;_Arg&nbsp;argument_type;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;_Result&nbsp;result_type;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span></div>
<p style="FONT-SIZE: 10pt"><br>关于predefined functor，如之前列举的plus一样，再列举一个：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;greater&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;binary_function</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Tp,&nbsp;_Tp,&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_79_194_Open_Image onclick="this.style.display='none'; Codehighlighter1_79_194_Open_Text.style.display='none'; Codehighlighter1_79_194_Closed_Image.style.display='inline'; Codehighlighter1_79_194_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_79_194_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_79_194_Closed_Text.style.display='none'; Codehighlighter1_79_194_Open_Image.style.display='inline'; Codehighlighter1_79_194_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;</span><span id=Codehighlighter1_79_194_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_79_194_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">()(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__y)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_151_187_Open_Image onclick="this.style.display='none'; Codehighlighter1_151_187_Open_Text.style.display='none'; Codehighlighter1_151_187_Closed_Image.style.display='inline'; Codehighlighter1_151_187_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_151_187_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_151_187_Closed_Text.style.display='none'; Codehighlighter1_151_187_Open_Image.style.display='inline'; Codehighlighter1_151_187_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_151_187_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_151_187_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;__x&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;__y;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p style="FONT-SIZE: 10pt">&nbsp;<br>关于functor adaptors，也是我觉得比较有趣的部分，多列举几个：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Operation,&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;inline&nbsp;binder1st</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Operation</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;bind1st(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Operation</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__fn,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Tp</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x)<br><img id=Codehighlighter1_122_252_Open_Image onclick="this.style.display='none'; Codehighlighter1_122_252_Open_Text.style.display='none'; Codehighlighter1_122_252_Closed_Image.style.display='inline'; Codehighlighter1_122_252_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_122_252_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_122_252_Closed_Text.style.display='none'; Codehighlighter1_122_252_Open_Image.style.display='inline'; Codehighlighter1_122_252_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_122_252_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_122_252_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;typename&nbsp;_Operation::first_argument_type&nbsp;_Arg1_type;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;binder1st</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">_Operation</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">(__fn,&nbsp;_Arg1_type(__x));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span></div>
<p style="FONT-SIZE: 10pt">&nbsp; <br>bind1st返回的binder1st定义为：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;template&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;_Operation</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;binder1st&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;unary_function</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">typename&nbsp;_Operation::second_argument_type,&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;typename&nbsp;_Operation::result_type</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_153_710_Open_Image onclick="this.style.display='none'; Codehighlighter1_153_710_Open_Text.style.display='none'; Codehighlighter1_153_710_Closed_Image.style.display='inline'; Codehighlighter1_153_710_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_153_710_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_153_710_Closed_Text.style.display='none'; Codehighlighter1_153_710_Open_Image.style.display='inline'; Codehighlighter1_153_710_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_153_710_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_153_710_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Operation&nbsp;op;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;_Operation::first_argument_type&nbsp;value;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;binder1st(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;_Operation</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;typename&nbsp;_Operation::first_argument_type</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__y):&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;op(__x),&nbsp;value(__y)&nbsp;<br><img id=Codehighlighter1_382_383_Open_Image onclick="this.style.display='none'; Codehighlighter1_382_383_Open_Text.style.display='none'; Codehighlighter1_382_383_Closed_Image.style.display='inline'; Codehighlighter1_382_383_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_382_383_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_382_383_Closed_Text.style.display='none'; Codehighlighter1_382_383_Open_Image.style.display='inline'; Codehighlighter1_382_383_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_382_383_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_382_383_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;_Operation::result_type&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">()(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;typename&nbsp;_Operation::second_argument_type</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_508_550_Open_Image onclick="this.style.display='none'; Codehighlighter1_508_550_Open_Text.style.display='none'; Codehighlighter1_508_550_Closed_Image.style.display='inline'; Codehighlighter1_508_550_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_508_550_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_508_550_Closed_Text.style.display='none'; Codehighlighter1_508_550_Open_Image.style.display='inline'; Codehighlighter1_508_550_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_508_550_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_508_550_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;op(value,&nbsp;__x);&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;_Operation::result_type&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">()(typename&nbsp;_Operation::second_argument_type</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;__x)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_666_706_Open_Image onclick="this.style.display='none'; Codehighlighter1_666_706_Open_Text.style.display='none'; Codehighlighter1_666_706_Closed_Image.style.display='inline'; Codehighlighter1_666_706_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_666_706_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_666_706_Closed_Text.style.display='none'; Codehighlighter1_666_706_Open_Image.style.display='inline'; Codehighlighter1_666_706_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_666_706_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_666_706_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;op(value,&nbsp;__x);&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p style="FONT-SIZE: 10pt">&nbsp;<br>值得一提的是，ptr_fun以及相关的pointer_to_unary_function, pointer_to_binary_function，基本上<br>就是用来绑定C函数的组件，不过这里采用了很基础的模板技术，因此只实现了绑定一个参数和两个参数<br>的C函数。这种组件类似于loki中的functor，以及boost中的bind，只是功能弱很多。与之相关的还有<br>mem_fun, mem_fun_ref, mem_fun1, mem_fun1_ref等，这些都是用于绑定成员函数的。另一方面，与其说<br>是绑定，还不如说适配，即将函数适配为functor(特指重载operator()的类)。( Mem_fun_t is an adaptor<br>&nbsp;for member functions )采用这些(ptr_fun, mem_fun之类的东西)组件，客端程序员可以很容易地将各种<br>运行体(Kevin似乎很喜欢发明各种名字)(C函数、成员函数)适配成functor，从而与STL泛型算法结合。<br>例如, SGI文档中给出的mem_fun例子：</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_9_38_Open_Image onclick="this.style.display='none'; Codehighlighter1_9_38_Open_Text.style.display='none'; Codehighlighter1_9_38_Closed_Image.style.display='inline'; Codehighlighter1_9_38_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_9_38_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_9_38_Closed_Text.style.display='none'; Codehighlighter1_9_38_Open_Image.style.display='inline'; Codehighlighter1_9_38_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;B&nbsp;</span><span id=Codehighlighter1_9_38_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_9_38_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">virtual</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print()&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_63_111_Open_Image onclick="this.style.display='none'; Codehighlighter1_63_111_Open_Text.style.display='none'; Codehighlighter1_63_111_Closed_Image.style.display='inline'; Codehighlighter1_63_111_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_63_111_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_63_111_Closed_Text.style.display='none'; Codehighlighter1_63_111_Open_Image.style.display='inline'; Codehighlighter1_63_111_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;D1&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;B&nbsp;</span><span id=Codehighlighter1_63_111_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_63_111_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_79_109_Open_Image onclick="this.style.display='none'; Codehighlighter1_79_109_Open_Text.style.display='none'; Codehighlighter1_79_109_Closed_Image.style.display='inline'; Codehighlighter1_79_109_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_79_109_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_79_109_Closed_Text.style.display='none'; Codehighlighter1_79_109_Open_Image.style.display='inline'; Codehighlighter1_79_109_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print()&nbsp;</span><span id=Codehighlighter1_79_109_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_79_109_Open_Text><span style="COLOR: #000000">{&nbsp;cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">I'm&nbsp;a&nbsp;D1</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;endl;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_136_184_Open_Image onclick="this.style.display='none'; Codehighlighter1_136_184_Open_Text.style.display='none'; Codehighlighter1_136_184_Closed_Image.style.display='inline'; Codehighlighter1_136_184_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_136_184_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_136_184_Closed_Text.style.display='none'; Codehighlighter1_136_184_Open_Image.style.display='inline'; Codehighlighter1_136_184_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;D2&nbsp;:&nbsp;</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;B&nbsp;</span><span id=Codehighlighter1_136_184_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_136_184_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_152_182_Open_Image onclick="this.style.display='none'; Codehighlighter1_152_182_Open_Text.style.display='none'; Codehighlighter1_152_182_Closed_Image.style.display='inline'; Codehighlighter1_152_182_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_152_182_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_152_182_Closed_Text.style.display='none'; Codehighlighter1_152_182_Open_Image.style.display='inline'; Codehighlighter1_152_182_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;print()&nbsp;</span><span id=Codehighlighter1_152_182_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_152_182_Open_Text><span style="COLOR: #000000">{&nbsp;cout&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">I'm&nbsp;a&nbsp;D2</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;endl;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_199_357_Open_Image onclick="this.style.display='none'; Codehighlighter1_199_357_Open_Text.style.display='none'; Codehighlighter1_199_357_Closed_Image.style.display='inline'; Codehighlighter1_199_357_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_199_357_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_199_357_Closed_Text.style.display='none'; Codehighlighter1_199_357_Open_Image.style.display='inline'; Codehighlighter1_199_357_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_199_357_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_199_357_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;vector</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">B</span><span style="COLOR: #000000">*&gt;</span><span style="COLOR: #000000">&nbsp;V;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;V.push_back(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;D1);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;V.push_back(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;D2);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;V.push_back(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;D2);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;V.push_back(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;D1);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;for_each(V.begin(),&nbsp;V.end(),&nbsp;mem_fun(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">B::print));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt">注：以上分析基于dev-cpp中自带的stl，源代码见stl_functional.h。</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<p style="FONT-SIZE: 10pt">&nbsp;</p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/44362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-03-13 13:31 <a href="http://www.cppblog.com/kevinlynx/archive/2008/03/13/44362.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最近接触的东西</title><link>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44322.html</link><dc:creator>Kevin Lynx</dc:creator><author>Kevin Lynx</author><pubDate>Wed, 12 Mar 2008 16:17:00 GMT</pubDate><guid>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44322.html</guid><wfw:comment>http://www.cppblog.com/kevinlynx/comments/44322.html</wfw:comment><comments>http://www.cppblog.com/kevinlynx/archive/2008/03/13/44322.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/kevinlynx/comments/commentRss/44322.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/kevinlynx/services/trackbacks/44322.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt">平时工作，很好有时间拿来自己安排学习，所以接触的东西比较杂乱。偶尔做个列表，列出最近完成的以及计划安排。<br><br>网络编程，摆弄各种API，其实弄明白了写点实验代码觉得什么都不是。当初想买TCP那三本龙书，想对底层探个究竟，可是终究还没能抽出时间。<br><br>网络库，网络库不是把socket不是把IOCP封装起来就可以的。再经历过各种架构，写过一些库代码后，自己对开发库的要求是越来越高。琢磨了良久，我心目中的网络库，即使是用来讨好自己的迷你型的，起码也该进行软件分层，从发送接收层到加解密层到数据校验层到消息层，这么多层次，要做好不容易。心里面其实有想法，无论如何，我应该秉持当初开发edge2d的态度，在真正动手之前先取万家之长。<br><br>MMO服务器分布式架构，不了解之前觉得宏大不可及，接触后其实也觉得没什么。凡事不要害怕，想想看，再深奥的东西，也是人想出来的。一个东西之所以复杂，是因为它经历了长久的变化。如果让我来想，如何通过服务器的分布式架构减轻单个服务器的负载，那我想出来的，最多是几年前的老东西。无论如何，分布式架构的模式在那里。关键是让自己去学着改善学着思考出自己的方案。本来安排了几个网络游戏代码让自己去读。可是竟然如此郁闷地找不到时间。<br><br>模板编程，想来做技术都秉持一个观点，一步一步来，不求多只求精。自己学C++分了好几个阶段，理论，实践，理论，实践。这样磨蹭着过来，一年时间竟也写了10万行代码。之前有过深入接触C++模板编程的想法，看了一阵子书，觉得基本上没获得一种模板实践编程的思想，果然是可学不可用的东西么？后来听说dophi说他们公司有个人被封为&#8216;模板达人&#8217;，自己觉得有点意思。于是08年又把模板拿出来。看了&lt;STL源码剖析&gt;，翻了下STL源码，确实有时候觉得精妙不可言，大有拍案叫绝的感觉。不过从本质上来说，也不过如此。最近又开始看&lt;C++设计新思维&gt;，之前看过英文电子版第一章，对于满世界的policy混沌不已。现在看纸质的书，觉得感觉还行，没有原先想像的那么神圣不可及。现在很高兴有了模板编程的思想，时髦点说是泛型思维。当初很善于玩弄面向对象架构，老喜欢给别人炫耀一个系统的架构（例如我的edge2d)，谈论各种设计模式。现在对于模板，也喜欢满世界地塞template，仿佛全世界都可以泛化一样。凡事有个度，不过自己允许自己在初期过于泛化吧。<br><br>自己模仿着loki写了个functor，觉得很美妙。打算将operator ==和copy constructor整理下就可以用于实践。<br><br>看了下stl的binary_function, unary_function, bind1st, bing2nd之类的functor, functor adapter，觉得真是粗糙不堪。不过我想，这种粗糙也情有可原，毕竟像loki这种挑战编译器极限的玩意，也只能算作程序员的炫耀品了吧？<br><br>准备看boost的bind，现在学技术老爱一杆子全部打下。学了网络编程就想多看几个网络库，自己写了线程池就想看看别人写的线程池，学了模板就四处找template看。so how about boost::bind ?<br><br>瞎摆弄了下asio，实在很想找个东西用来实践下，不想leader不允许。这世界，可学不可用的东西太多太多。<br><br>准备接触linux下的epoll，幻想着它也许就是一个轮询的查询方式，似乎还没IOCP来得优美。也许真正开始linux编程的时候，我也就真正不会使用exception。但是起码现在的观点是，鄙视那些因为C++的高级特性（多态异常所有你能想到的）而带来的C++的所谓低效率的人。如果你认为那么一点点语言机制会拖慢你系统的运行速度，那么你为什么不去看看你那些蜗牛一样的算法？如果你在用C++，那么专业点，努力不要写C风格的class（很别扭，是吧），努力进入C++的世界。我不是C++牛人，因此我不能告诉你C++标准库，C++准标准库，C++那么多那么多优秀的库，为什么要那样做，为什么要使用多态将整个系统抽象起来，为什么要用异常将整个系统throw起来，为什么那么多稀奇古怪的template typename。我只知道，我在写C++程序，所以我跟随这些库的作者。<br><br>内存池，不单单是内存池吧?总之关于自己管理内存的东西，STL里面有allocator(限于SGI的STL），loki里有SmallObject，这些都是不错的东西。如果可以，我会去实现一个allocator，内存分配器。但是如果折中，我会剥离STL的allocator，记住，policy设计方法学告诉我们，组装这些组件！<br><br>线程池，其实原理就那么简单。分配一堆取着用先，不够了再分配，积极回收吧。但是出于对自己多线程编程经验的不自信，我最终不敢炫耀我自己实现的线程池。我想，先培养我和多线程的感情先吧。<br><br>凌乱杂散了这么多，接下来换换重心，集中攻克一方面吧。<br><br></p>
<img src ="http://www.cppblog.com/kevinlynx/aggbug/44322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/kevinlynx/" target="_blank">Kevin Lynx</a> 2008-03-13 00:17 <a href="http://www.cppblog.com/kevinlynx/archive/2008/03/13/44322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>