<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>随.心.所.记 &#187; 类型推导</title>
	<atom:link href="http://www.realdodo.com/tag/%e7%b1%bb%e5%9e%8b%e6%8e%a8%e5%af%bc/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.realdodo.com</link>
	<description>享受生活的乐趣与烦恼</description>
	<lastBuildDate>Fri, 25 Jun 2010 18:49:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>boost中如何面对疯狂的类型推导？</title>
		<link>http://www.realdodo.com/2007/05/06/176/</link>
		<comments>http://www.realdodo.com/2007/05/06/176/#comments</comments>
		<pubDate>Sun, 06 May 2007 15:33:00 +0000</pubDate>
		<dc:creator>realdodo</dc:creator>
				<category><![CDATA[技术文章]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[boost.spirit]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[C++ 0X]]></category>
		<category><![CDATA[C++模板]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[类型推导]]></category>

		<guid isPermaLink="false">http://www.realdodo.com/2007/05/06/176/</guid>
		<description><![CDATA[这些天，我一直在说一个名词：Expression Templates。这个东西很有用，我也会在未来把这篇英文文档用易懂的中文讲解一遍（当然，各位已经看过的高手可以无视我未来的这篇文章）。 可以很肯定地说，Expression Templates一定是未来C++各种类库设计的标准思路，现在boost.spirit、boost.lambda、boost.uBLAS、boost.xpressive等库都是用这种思路设计，而且介绍这种方法的论文也明确指出，合理应用这种方法可以显著的提高程序性能，能让C++程序库的效率高于相同功能的C程序库（例如std::sort和qsort的比较）。但是它的一个致命缺点是：令人发狂的类型推导。 看看下面这个例子吧，它是boost.spirit的一个例子（boost 1.34.0的libs/spirit/example/techniques/no_rules/no_rule2.cpp），用于说明如果没有自动类型推导或者类似功能的机制，类型定义会变得多么的疯狂： 程序代码 struct skip_grammar : grammar&#60;skip_grammar&#62; {     template &#60;typename ScannerT&#62;     struct definition     {         definition(skip_grammar const&#38; /*self*/)         : skip             (       space_p                 &#124;   &#8221;//&#8221; &#62;&#62; *(anychar_p - &#8217;\n&#8217;) &#62;&#62; &#8217;\n&#8217;                 &#124;   &#8221;/*&#8221; &#62;&#62; *(anychar_p - &#8221;*/&#8221;) &#62;&#62; &#8221;*/&#8221;             )         {         }         typedef            alternative&#60;alternative&#60;space_parser, sequence&#60;sequence&#60;            strlit&#60;const char*&#62;, kleene_star&#60;difference&#60;anychar_parser,            chlit&#60;char&#62; &#62; &#62; &#62;, chlit&#60;char&#62; &#62; &#62;, sequence&#60;sequence&#60;            strlit&#60;const char*&#62;, kleene_star&#60;difference&#60;anychar_parser,            strlit&#60;const char*&#62; &#62; &#62; &#62;, strlit&#60;const char*&#62; &#62; &#62;         skip_t;         skip_t skip;         skip_t const&#38; start() const { return skip; }     }; }; 请注意中间的那个skip_t的类型定义，我相信一定没有人相信是人手写出来的……本来应该编译器做的事情换做人来做，太疯狂了！特别是还要自己弄明白所有的operator的返回类型，更加的困难…… boost.spirit的作者Joel de Guzman给出了一个比较猥琐的解决方案：将skip_t先定义成随便一个什么类型，比如int，然后编译，这样便一起就会提示说：“Cannot convert boost::spirit::alternative&#60;&#8230; &#8230;&#8230;&#8230;&#8230;&#62; to int”，把这个错误拷贝出来，就可以看到实际的类型了——天哪，足够疯狂了！这还没完，如果遇到更复杂的情况怎么办，看看boost 1.34.0的libs/spirit/example/techniques/no_rules/no_rule3.cpp吧，头开始疼了…… 所以，Joel de Guzman在给我留下深刻印象之后开始说明他的方案。 方案一：期待C++ 0X早日成为事实的标准，让那个非常有用的auto关键字成为到处可用的东西。 方案二：使用部分编译器已经实现的typeof关键字，然后写一个宏： 程序代码 #define RULE(name, definition) typeof(definition) name = definition 这样，就可以简单的使用宏来简化各种类型定义，不过可怜的MSVC并没有实现这种功能。 方案三：使用“Nabialek trick”。看到“Nabialek trick”这个陌生的名词，我的第一个反应就是“去google/baidu”，不过很可惜，google上的所有搜索结果都直接或间接的来自我正在看的boost.spirit文档，而baidu更是告诉我找不到。OK，我们还是回到这个名词本身吧。这个trick是因为其发明者，Sam Nabialek，而得名，其作用是将“线性非决定式”（linear non-deterministic）转换成“决定式”（deterministic）。如果要说的更具体一些就不行了，其实我还不太明白，我正在阅读boost.spirit的部分源码，希望能够有些收获。无论如何，boost.spirit最终用极为优雅的方式将类型推导的难题再次交给了编译器，整个代码非常的简洁明了，可谓是最佳的实现方式。 就我个人来说，应该还可以提出方案四：使用boost.typeof库的基础设施，不过为了能使用这个东西，依然必须手动的“注册”各种类型，并依赖于大量的模板和宏技巧，比较烦，所以并不算一个很好的方式，但至少还可以接受。 综合来说，正是因为Expression Templates的广泛使用，类型推导成了一个疯狂的怪兽，而C++ 0X中的auto关键字成了绝对的救星，我们还是来呼唤新标准早日降临吧！]]></description>
			<content:encoded><![CDATA[<p>这些天，我一直在说一个名词：<a href="http://ubiety.uwaterloo.ca/~tveldhui/papers/Expression-Templates/exprtmpl.html" target="_blank">Expression Templates</a>。这个东西很有用，我也会在未来把这篇英文文档用易懂的中文讲解一遍（当然，各位已经看过的高手可以无视我未来的这篇文章）。</p>
<p>可以很肯定地说，<a href="http://ubiety.uwaterloo.ca/~tveldhui/papers/Expression-Templates/exprtmpl.html" target="_blank">Expression Templates</a>一定是未来C++各种类库设计的标准思路，现在boost.spirit、boost.lambda、boost.uBLAS、boost.xpressive等库都是用这种思路设计，而且介绍这种方法的论文也明确指出，合理应用这种方法可以显著的提高程序性能，能让C++程序库的效率高于相同功能的C程序库（例如std::sort和qsort的比较）。但是它的一个致命缺点是：令人发狂的类型推导。</p>
<p>看看下面这个例子吧，它是boost.spirit的一个例子（boost 1.34.0的libs/spirit/example/techniques/no_rules/no_rule2.cpp），用于说明如果没有自动类型推导或者类似功能的机制，类型定义会变得多么的疯狂：</p>
<div class="UBBPanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">struct skip_grammar : grammar&lt;skip_grammar&gt;<br />
{<br />
    template &lt;typename ScannerT&gt;<br />
    struct definition<br />
    {<br />
        definition(skip_grammar const&amp; /*self*/)<br />
        : skip<br />
            (       space_p<br />
                |   &#8221;//&#8221; &gt;&gt; *(anychar_p - &#8217;\n&#8217;) &gt;&gt; &#8217;\n&#8217;<br />
                |   &#8221;/*&#8221; &gt;&gt; *(anychar_p - &#8221;*/&#8221;) &gt;&gt; &#8221;*/&#8221;<br />
            )<br />
        {<br />
        }<br />
        typedef<br />
           alternative&lt;alternative&lt;space_parser, sequence&lt;sequence&lt;<br />
           strlit&lt;const char*&gt;, kleene_star&lt;difference&lt;anychar_parser,<br />
           chlit&lt;char&gt; &gt; &gt; &gt;, chlit&lt;char&gt; &gt; &gt;, sequence&lt;sequence&lt;<br />
           strlit&lt;const char*&gt;, kleene_star&lt;difference&lt;anychar_parser,<br />
           strlit&lt;const char*&gt; &gt; &gt; &gt;, strlit&lt;const char*&gt; &gt; &gt;<br />
        skip_t;</div>
<p>        skip_t skip;<br />
        skip_t const&amp; start() const { return skip; }<br />
    };<br />
};</p></div>
<p>请注意中间的那个skip_t的类型定义，我相信一定没有人相信是人手写出来的……本来应该编译器做的事情换做人来做，太疯狂了！特别是还要自己弄明白所有的operator的返回类型，更加的困难……</p>
<p>boost.spirit的作者Joel de Guzman给出了一个比较猥琐的解决方案：将skip_t先定义成随便一个什么类型，比如int，然后编译，这样便一起就会提示说：“Cannot convert boost::spirit::alternative&lt;&#8230; &#8230;&#8230;&#8230;&#8230;&gt; to int”，把这个错误拷贝出来，就可以看到实际的类型了——天哪，足够疯狂了！这还没完，如果遇到更复杂的情况怎么办，看看boost 1.34.0的libs/spirit/example/techniques/no_rules/no_rule3.cpp吧，头开始疼了……</p>
<p>所以，Joel de Guzman在给我留下深刻印象之后开始说明他的方案。<br />
方案一：期待C++ 0X早日成为事实的标准，让那个非常有用的auto关键字成为到处可用的东西。<br />
方案二：使用部分编译器已经实现的typeof关键字，然后写一个宏：</p>
<div class="UBBPanel">
<div class="UBBTitle">程序代码</div>
<div class="UBBContent">#define RULE(name, definition) typeof(definition) name = definition</div>
</div>
<p>这样，就可以简单的使用宏来简化各种类型定义，不过可怜的MSVC并没有实现这种功能。<br />
方案三：使用“Nabialek trick”。看到“Nabialek trick”这个陌生的名词，我的第一个反应就是“去google/baidu”，不过很可惜，google上的所有搜索结果都直接或间接的来自我正在看的boost.spirit文档，而baidu更是告诉我找不到。OK，我们还是回到这个名词本身吧。这个trick是因为其发明者，Sam Nabialek，而得名，其作用是将“线性非决定式”（linear non-deterministic）转换成“决定式”（deterministic）。如果要说的更具体一些就不行了，其实我还不太明白，我正在阅读boost.spirit的部分源码，希望能够有些收获。无论如何，boost.spirit最终用极为优雅的方式将类型推导的难题再次交给了编译器，整个代码非常的简洁明了，可谓是最佳的实现方式。</p>
<p>就我个人来说，应该还可以提出方案四：使用boost.typeof库的基础设施，不过为了能使用这个东西，依然必须手动的“注册”各种类型，并依赖于大量的模板和宏技巧，比较烦，所以并不算一个很好的方式，但至少还可以接受。</p>
<p>综合来说，正是因为<a href="http://ubiety.uwaterloo.ca/~tveldhui/papers/Expression-Templates/exprtmpl.html" target="_blank">Expression Templates</a>的广泛使用，类型推导成了一个疯狂的怪兽，而C++ 0X中的auto关键字成了绝对的救星，我们还是来呼唤新标准早日降临吧！</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save">分享/收藏</a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.realdodo.com/2007/05/06/176/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
