﻿<?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>IT博客-黎明-随笔分类-纯粹C++ </title><link>http://www.cnitblog.com/dlpresident/category/6456.html</link><description>从这里起步－－通向软件颠峰</description><language>zh-cn</language><lastBuildDate>Wed, 28 Sep 2011 07:49:20 GMT</lastBuildDate><pubDate>Wed, 28 Sep 2011 07:49:20 GMT</pubDate><ttl>60</ttl><item><title>Visual C++使用中的问题讨论</title><link>http://www.cnitblog.com/dlpresident/archive/2007/10/29/35559.html</link><dc:creator>董礼</dc:creator><author>董礼</author><pubDate>Mon, 29 Oct 2007 15:19:00 GMT</pubDate><guid>http://www.cnitblog.com/dlpresident/archive/2007/10/29/35559.html</guid><description><![CDATA[<p>Boost如何让VC6以实现mem_fun可以接收返回值为void的成员函数</p>
<p>VC6自带的STL，mem_fun可以接收的成员函数返回值不能为void。<br>在&lt;functional&gt;文件中可以看到具体的实现代码为：</p>
<p>template&lt;class _Return, class _Type&gt;<br>class mem_fun_t<br>{<br>public:<br>//construction...</p>
<p>_Return operator()(_Type *_P) const<br>{return ((_P-&gt;*_FuncPtr)()); }<br>private:<br>//member function pointer ...<br>};</p>
<p>当_Return为void时，VC6会报一个编译错误：void' function returning a value。</p>
<p>有心想解决一下。首先，尝试使用static_cast。</p>
<p>_Return operator()(_Type *_P) const<br>{return static_cast&lt;void)((_P-&gt;*_FuncPtr)()); }</p>
<p>发现报同样错误，看来VC6确实对标准支持一般。</p>
<p><br>然后当然想采用特化，对返回值类型进行void特化，但是VC6根本不支持部分特化，例如：</p>
<p>template&lt;class _Type&gt;<br>class mem_fun_t&lt;void, _Type&gt;<br>{..<br>};<br>报编译错误，重复的模板定义。 template class has already been defined as a non-template class</p>
<p>幸亏VC仍然支持完全特化，于是采用&#8220;增加一层&#8220;定律，由于只有返回值为void的时侯需要特别处理，<br>因此定义一个通用模板，然后对void进行完全特化：</p>
<p>template &lt;class Return&gt; struct return_trait<br>{<br>...<br>};</p>
<p><br>template&lt;&gt; struct return_trait&lt;void&gt;<br>{<br>...<br>};</p>
<p>下面的代码就是根据boost实现来的，简化了很多。毕竟阅读困难。</p>
<p>在这两者之间就可以对返回类型为void的情况进行特别处理了：<br>通用模板定义如下：<br>template &lt;class Return&gt; struct return_trait<br>{<br>template&lt;class Return, class Type, class F&gt; <br>struct inner_mem_fun_type<br>{<br>F func_;<br>inner_mem_fun_type(F f) : func_(f) {}</p>
<p>Return operator()(Type * type)<br>{<br>return (type-&gt;*func_)();<br>}<br>｝<br>};</p>
<p>void的完全特化模板和上面一模一样，只是将<br>return (type-&gt;*func_)();<br>中的return去掉即可，就不多写了。其中boost使用了宏和#include来实现这个功能。</p>
<p>然后定义一个模板函数，用来自动实例化合适的模板类型；<br>template&lt;class Return, class Type&gt; <br>return_trait&lt;Return&gt;::inner_mem_fun_type&lt;Return, Type, Return (Type::*)()&gt; <br>mem_func(Return (Type::*f)())<br>{<br>return return_trait&lt;Return&gt;::inner_mem_fun_type&lt;Return, Type, Return (Type::*)()&gt;(f);<br>}</p>
<p>boost其实在mem_fn中又创建了一个间接层次，我发现上面直接返回内嵌类VC6也可以编译。可能是因为其他的编译器需要这样处理。其中inner_mem_fun_type接收3个参数，第3个参数为成员函数指针类型，完全可以由Return,Type确定，但是发现如果不加上这个，VC6出现internal compiler error。我在这上面就折腾了很久。也不知道boost是如何发现这个解决方法的。</p>
<p><br>举一反三，对于类似的部分特化的需求，在VC6下都应该可以使用该方法解决。<br>例如，一个模板类有2个类型参数T1, T2，其中需要对int, T2进行部分特化处理。</p>
<p>最标准的当然是<br>template&lt;class Type1, class Type2&gt; struct Foo<br>{<br>...<br>};</p>
<p>对int, Type2部分特化<br>template&lt;class Type2&gt; struct&lt;int, Type2&gt;Foo<br>{<br>...<br>};</p>
<p>前面说了VC6不支持这种部分特化，因此可以如下；<br>提出Type1，定义一个嵌套结构：<br>template&lt;class Type1&gt; struct type_traits<br>{<br>template&lt;class Type1, class Type2&gt; struct Foo<br>{<br>};<br>};</p>
<p>对Type1为int进行完全特化：<br>template&lt;&gt; struct type_traits&lt;int&gt;<br>{<br>template&lt;class Type1, class Type2&gt; struct Foo<br>{<br>};<br>};</p>
<p>使用之：</p>
<p>type_traits&lt;double&gt;::Foo&lt;double, double&gt; f1;<br>type_traits&lt;int&gt;::Foo&lt;int, double&gt; f2;</p>
<p>很好。但是毕竟毕竟繁琐，当然想搞个模板成员函数推演出来：</p>
<p>template&lt;class Type1, class Type2&gt;<br>type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt; make_foo(Type1 t1, Type2 t2)<br>{<br>return type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt;(t1, t2);<br>}</p>
<p>结果到这一步又是internal compiler error。</p>
<p>看来还又得学习boost中的，使用继承关系。再来：</p>
<p>定义一个Wapper class，从嵌套类type_traits::Foo派生</p>
<p>template&lt;class Type1, class Type2&gt; <br>struct FooWapper : public type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt;<br>{<br>FooWapper(Type1 t1, Type2 t2) : type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt;(t1, t2) {}<br>};</p>
<p>maker函数返回FooWapper模板类，而不是嵌套的模板类<br>template&lt;class Type1, class Type2&gt;<br>FooWapper&lt;Type1, Type2&gt; make_foo(Type1 t1, Type2 t2)<br>{<br>return FooWapper&lt;Type1, Type2&gt;(t1, t2);<br>}</p>
<p>再试：<br>make_foo(1, 2.0);<br>make_foo('a', 2.0);</p>
<p>编译成功。测试也对。通过这种手法，应该可以在VC6下解决一部分部分特化的问题，如果需要特化的类型以定的话。但是想对例如T*这种进行指针特化估计是没有希望了。不错。boost！</p>
<p>完整的源程序：</p>
<p>//通用Type1, Type2<br>template&lt;class Type1&gt; struct type_traits<br>{<br>template&lt;class Type1, class Type2&gt; struct Foo<br>{<br>Foo(Type1 t1, Type2 t2)<br>{<br>std::cout &lt;&lt; "noint+type1" &lt;&lt; std::endl;<br>}<br>};<br>};</p>
<p>//特化的int，Type2<br>template&lt;&gt; struct type_traits&lt;int&gt;<br>{<br>template&lt;class Type1, class Type2&gt; struct Foo<br>{<br>Foo(Type1 t1, Type2 t2)<br>{<br>std::cout &lt;&lt; "int+type2" &lt;&lt; std::endl;<br>}<br>};<br>};</p>
<p>//Wrapper 类<br>template&lt;class Type1, class Type2&gt; <br>struct FooWapper : public type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt;<br>{<br>FooWapper(Type1 t1, Type2 t2) : type_traits&lt;Type1&gt;::Foo&lt;Type1, Type2&gt;(t1, t2) {}<br>};</p>
<p><br>//maker函数用于推演<br>template&lt;class Type1, class Type2&gt;<br>FooWapper&lt;Type1, Type2&gt; inline make_foo(Type1 t1, Type2 t2)<br>{<br>return FooWapper&lt;Type1, Type2&gt;(t1, t2);<br>}</p>
<p>//测试程序<br>int main()<br>{<br>make_foo(1, 2.0); //调用特化的&lt;int, type2&gt;<br>make_foo('a', 2.0); //调用通用的&lt;type1, type2&gt;<br>}<br></p>
<img src ="http://www.cnitblog.com/dlpresident/aggbug/35559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/dlpresident/" target="_blank">董礼</a> 2007-10-29 23:19 <a href="http://www.cnitblog.com/dlpresident/archive/2007/10/29/35559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>