模板元程序 (十)

来源:互联网 发布:js urlencode 中文解码 编辑:程序博客网 时间:2024/05/16 19:05


2.9 一些细节
在这一章中我们已经讨论了很多的基础。从 traits 到元函数的旅程,将我们从最简单的泛型程序的类型关联,引入到了使得元程序编程可以看成是一级代码实践的基础原则。我们也深挖了 C++ 模板机制,对于 type traits 库有了一个大概的了解,并且看到了它实际的一些组件,在这样的一个广阔领域里,一个重要的细节却被忽视了。我们将在回顾这章重点的时候将它们补回来。


特化
用在 C++ 模板中的特化的含意很难于解释,因为它有两种不同的使用方式。第一种指用特定的参数来引用模板,如 iterator_traits<int*>。换句话说,一个模板特化实际上是指的类型(在函数模板特化的情况下是函数),这是通过将模板的形参用特定的参数来替换而得到了。

第二种特化的使用,则出现在“显式物化” 和 “部分特化” 中。在这一种章中我们已经展示了 iterator_traits 的这两种特化方式。“名字”显式“也许并不是很准确,因为”部分特化”也是一种显式的。你可以将“显式特化”看成是“完全特化”,但却没有失去其原有含义。
回忆一下声明类模板特化的语法规范(第二种含义),只要记住下面的方式:

    template <variable part>
    struct template-name<fixed part>


在显式特化(或者是完全特化)中,variable part 是空的,而 fixed part 由具体的模板参数组成。在部份特化中,variable part 是一个参数列表,并且至少有一个 fixed part 中的参数依赖于这个列表中的参数。


主模板
声明成非特化(第二种特化含义)的模板,我们就称为主模板,我们可以认为主模板是应对通用情况,而特化则是针对几种特别情况。


实例化
当编译器需要知道模板更多更详细的参数,而不仅仅是他的参数是其成员函数的名字或者是其基类的标识符时,则被称为实例化。如模板被实现。在这个点上,编译器用实际的模板参数填入模板参数,并且选择最匹配的显式特化或者部分特化(如果有)。并且指出用在模板体中使用的类型及常数。并且重新检查这些声明的是否正确。但并不实例化定义(如成员函数体),而直到他们被使用时才会这么做。如:

    template <class T, class U>
    struct X
    {
        int f(T* x) // 声明
        {
           U y[10]; // 定义
           return 0;
        }
    };

    typedef X<int&, char> t1; // OK; 未实例化
    t1 x1;                    // 错误,指向 int& 的指针非法
    typedef X<int, char&> t2;
    t2 x2;                    // OK; 声明通过
    int a = x2.f();           // 错误: char & 的数据非法
   
正如你所见,模板的实现化不仅能影响到编译速度,同时也影响你的编译是否可以通过。
   
Blob
就是一个类型中,带有许多的成员(包括成员函数),在面向对象的编程中就称为“blob”[BMMM98]。类型中的所有成员都是相互“偶合的”,因为他们必须被声明在一起。为了避免偶合,并且提高粒度,应该反对这样的反模式。相反,应该将这些 traits 定义成分离的元函数。

元数据

就是能够被 C++ 编译期机制所操作的 “value”,我们都可以认为它是元数据。在模板元程序中,两种最通常的元数据就是类型与整数(包括 bool)常数。在 C++ 的编译期部分通常都表示成一种“纯函数语言”,因为元数据是不可变的,而元函数不能有任何的副作用。

多态
在字面上来讲,就是“拥有多种形式”。在计算机语言中,多态指的是通过一个共同接口操作不同类型的能力。拥有一致的接口是保证代码可重用及组件间自然交互的最好方法。因为 C++ 模板并非天生将不同类型的元数据进行多态化看待, MPL 因此按照非类型元数据换装在类型元数据中的习惯来完成多态。特别地,数值元数据在一个类型中出现为一个内嵌的数值常数 ::value。

元函数
就是在编译期调用的使用元数据的“函数”。在此书的后面部分,一个模板或者一个类能被称为一个元函数,仅在其没有非类型的参数,并且返回一个称为 type 的类型。输入给类模板的参数,同时也是编译期计算的输入。而 ::type 就是其结果,因此如下的表达式:
 
 some_metafunction<Arg1, Arg2>::type
 
与运行时的计算有相似:
 some_function(arg1, arg2)

数值元函数
就是为一个数值返回一个包装类的元函数。为了方便,许多的数值元函数本身提供了一个内嵌的 ::value 成员,通过这样来直接访问数值结果:

some_numerical_metafunction<Arg>::value

而不用这样写:

some_numerical_metafunction<Arg>::type::value

空元函数
就是有公共可访问的 ::type,并且可用作接受0个参数的元函数使用的类。根据定义,任何一个元函数的特化(上面第一种含义),像 boost::remove_pointer<char*> 都是合法的空元函数。

Traits
通过类模板特化在不同的元数据之间建立关联的技术。 traits 的一个关键特性就是它是非侵入式的:我们可以在不修改被关联项的情况下重新创建新的关联。MPL 元函数则被看成是 traits 的一个特例,MPL 的元函数对于任何一个输入都只有一个输出。

Type traits
Boost Type Traits 库是一个元函数库,它包含了一些低阶的类型操作元函数,例如, add_reference 的结果就是一个 reference:
    boost::add_reference<char>::type      // char&
    boost::add_reference<int&>::type      // int&

Type Traits 主要由 bool 元函数组成,这些元函数可用来判断任何的类型的特性。便如:

    boost::is_reference<char>::value      // false
    boost::is_reference<int&>::value      // true

原创粉丝点击