Boost 元编程学习笔记(四)
Bruce Wang Email:b-zwang@hotmail.com
元函数
如果你已经注意到了在traits模板和普通函数之间的类似点,那么,非常好!traits模板的参数和嵌套类型在编译期扮演了和运行期的函数参数、返回值类似的角色。除了用类型传递和返回代替了值,traits模板展示了两个重要的特征,这是我们在普通函数中看不到的。
专门化.我们仅仅通过为traits的特殊值类型参数添加一个专门化,我们就能非侵入性的改变traits模板的结果。通过局部专门化,我们甚至能为值的全程范围改变结果。如果你能在常规函数中运用它,专门化将是真正陌生的东西。想象一下,我们能为std::abs添加一个重载,而使std::abs只有他的参数是奇数时才被调用!
? 多返回值。在普通函数映射他们的参数到一个值时,traits 经常有多个结
果。例如:std::iterator_traits包含了5个被嵌套的类: value_type, reference, pointer, difference_type, 和iterator_category. 去发现traits模板包含了嵌套常量或静态成员函数并不是什么不寻常的事。Traits在标准库中仅仅是这种组件的一个例子而已。
?
我们使用元函数这个术语,去保持“类模板作为函数”的这个想法。元函数是Boost元编程库的主要抽象概念, 正确理解和使用它们是开启Boost元编程库力量的关键钥匙。以后我们会继续深入的讨论元函数,但是在这里,我们需要解释下元函数和典型的traits之间的重要区别。
标准库中的 traits模板都遵守多返回值的模式。我们所引用的这种traits就像是一个”bolb”,因为它虽然是分离的并且松散的,但相关的元函数被对齐在一起作为一个单独的单元组件。我们必须回避这个术语带来的成本,因为他会给我们带来太多的麻烦。那么什么是‘bolb’呢?一个类有很多的成员,包括成员函数,在面向对象的编程文化中就被看作是一个‘bolb’。一个类的所有成员相对另一个成员必须是耦合的,因为他们必须被声明在一起。为了回避这种耦合和增长的模块化,更为了回避这种反模式,我们定义了分离的traits作为独立的元函数。什么又是反模式呢?它是一个需要回避的术语,因为反模式降低了程序的互操作性,或者说降低了程序组件平滑的工作在一起的能力。
首先,有一个效率问题:我们第一次在iterator_traits中搜索::value_type,模板将被实例化。这意味着编译器要做很多事,对于我们最重要的是编译器必须计算出那些和模板参数发生依赖关系的模板体中的每个声明的意义。在
iterator_traits的案例中,那意味着计算的不仅是value_type, 而且要计算其他4
个被联合的类型,尽管我们没有使用它们。这个额外类型计算的代价是使程序变大,降低编译周期。还记得吗?我们说过类型计算更加有趣,但更加有趣对你的编译器而言,就意味着有更多的工作,你也会能多的时间一边看着编译编译进度,一边在桌上掂着你的手指等待。
其次,也是更重要的,如果我们的元函数需要用其它的元函数作为参数,bolb干涉了我们写这种元函数的能力。围绕这一点,我们考虑一个琐碎的运行期函数,它有两个函数参数。
template
return f(g(x)); }
这不是我们能设计apply_fg的唯一方式,假设我们合并了f和g 作为一个参数,称为blob,像下面这样:
template
returnblob.f(blob.g(x)); }
去调用f和g的方式与你访问一个\的方式是类似的: 为了获得函数的结果,你搜索并访问它的成员,问题在于不仅仅只有一种方式去获得那些blob调用结果。为了传递f或g给另一,每个像apply_fg 这样的函数都将使用它自己的成员函数集,所以我们可能需要用新的名字包装这样的函数。当apply_fg使用了单一协议时,我们能很容易的替换他们:
#include
int a = apply_fg(5.Of, std::negate
允许不同的参数类型被用来相互交换的属性被称为多态,从字面上讲就是使用多种形态的能力。在元函数中,为了达到多态,我们需要一个单一的方式去调用他们,通过使用Boost库,这是很方便的,就像下面这样:
metafunction-name
相关推荐: