作者:realdodo 来源:realdodo.com 酷勤网收集 2007-09-13
摘要
Expression Templates一定是未来C++各种类库设计的标准思路,现在boost.spirit、boost.lambda、boost.uBLAS、boost.xpressive等库都是用这种思路设计,而且介绍这种方法的论文也明确指出,合理应用这种方法可以显著的提高程序性能
可以很肯定地说,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<skip_grammar>
{
template <typename ScannerT>
struct definition
{
definition(skip_grammar const& /*self*/)
: skip
( space_p
| "//" >> *(anychar_p - '\n') >> '\n'
| "/*" >> *(anychar_p - "*/") >> "*/"
)
{
}
typedef
alternative<alternative<space_parser, sequence<sequence<
strlit<const char*>, kleene_star<difference<anychar_parser,
chlit<char> > > >, chlit<char> > >, sequence<sequence<
strlit<const char*>, kleene_star<difference<anychar_parser,
strlit<const char*> > > >, strlit<const char*> > >
skip_t;
skip_t skip;
skip_t const& start() const { return skip; }
};
};
请注意中间的那个skip_t的类型定义,我相信一定没有人相信是人手写出来的……本来应该编译器做的事情换做人来做,太疯狂了!特别是还要自己弄明白所有的operator的返回类型,更加的困难……
boost.spirit的作者Joel de Guzman给出了一个比较猥琐的解决方案:将skip_t先定义成随便一个什么类型,比如int,然后编译,这样便一起就会提示说:“Cannot convert boost::spirit::alternative<... ............> 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关键字成了绝对的救星,我们还是来呼唤新标准早日降临吧!

