Andrei Alexandrescu的<<Modern C++ Design>>这本书的第三章向大家展示了template metaprogramming的魅力,中文版由侯捷和于春景翻译。在这章中,对于Typelist的求长度,索引,添加等操作的模板使用技巧的确令人眼花缭乱,惊叹不已!我们在看书过程中可能对这些模板的实现细节粗略浏览了下,其中有几个模板的细节技巧非常的精妙复杂,难以领会和掌握,我们很可能跳过这些细节,心中揣着“只要能运用Andrei所做的结果就OK了,实现细节嘛,……”的想法,继续去攻占该书的其他部分。
在该书的序言部分,John Vilissides是这样形容第三章的:”Some of the techniques herein are admittedly tricky to grasp, especially the template metaprogramming in Chapter 3. Once you've mastered that, however, you'll have a solid foundation for the edifice of generic componentry, which almost builds itself in the ensuing chapters.”
“无可否认,这里的一些技术很复杂,因而难以领会,特别是第三章的template metaprogramming部分。但是一旦你掌握了它,你就奠定了范型组件架构的坚实基础;后续章节中的各个范型组件几乎就是自己构造自己。”
因此,在该章节上,我花了大量的时间,反复阅读,希望能对metaprogramming有更深的理解。当该书中操作Typelist的前面几个模板的实现在我看起来已经不是那么“不自然”时,我开始阅读3.12节 – 为Typelist局部更换次序(Partially Ordering),该书举了个例子,将
TYPELIST_4(Widget, ScrollBar, Button, GraphicButton)转换为TYPELIST_4(ScrollBar, GraphicButton, Button, Widget).该书代码中的DerivedToFront的实现细节很显然地没有对DerivedToFront模板自身进行递归,因此相关操作只进行了一次就结束了(Loki库的源代码中已经修正了这个错误),因此该例子是错误的。
更可惜的是, TYPELIST_4(Widget, ScrollBar, Button, GraphicButton)进行DerivedToFront操作之后并不是变成了TYPELIST_4(ScrollBar, GraphicButton, Button, Widget)。
看测试例子,
#include <iostream>
#include "loki/Typelist.h"
class Widget {};
class ScrollBar: public Widget {};
class Button: public Widget {};
class GraphicButton: public Button {};
int main()
{
using namespace Loki::TL;
/// Better prefer "MakeTypelist" template function rather than "TYPELIST_n" Macro
/// TYPELIST_2(MyClass<int, double>, float), the first comma between "int" and
/// “double”which are both arguments inside the "MYClass" template class’s
/// argument list would cause problem!
typedef MakeTypelist<Widget, ScrollBar, Button, GraphicButton>::Result Controls;
typedef DerivedToFront<Controls>::Result OrderedControls;
std::cout << typeid(TypeAt<OrderedControls, 0>::Result).name() << ‘\n’;
std::cout << typeid(TypeAt<OrderedControls, 1>::Result).name() << ‘\n’;
std::cout << typeid(TypeAt<OrderedControls, 2>::Result).name() << ‘\n’;
std::cout << typeid(TypeAt<OrderedControls, 3>::Result).name() << std::endl;
}
这里使用的typeid返回的std::type_info对象的name函数进行查看类型名称(这里只是测试,而且是在vc7.1里测试,其他编译器name可不一顶乖乖输出该类型的名称)。
结果是,
class GraphicButton
class ScrollBar
class Button
class Widget
换成Typelist的话来说就是,TYPELIST_4(GraphicButton, ScrollBar, Button, Widget)!
因此,书中的例子是完全错误的。
可能原书中存在着这两个错误,然后“遗传”到了中文版中。很奇怪,为什么两位译者也居然没留意这两个错误。^^.看来也没仔细看哦!光顾着翻译了~~~~~~.