跳转到内容

更多 C++ 惯用法/策略克隆

来自维基教科书,开放的书籍,开放的世界

策略克隆

[编辑 | 编辑源代码]

使用许多不同的可能类型实例化策略类,而不对策略类的类型进行临时限制。

也称为

[编辑 | 编辑源代码]

使用基于策略的类设计技术可以构建高度可重用、灵活且可扩展的类。有时,策略的宿主类需要创建一个其实例化策略的精确副本,但使用不同的类型参数。不幸的是,宿主类模板的编写者事先不知道要实例化的模板名称。此外,策略类本身可能或可能不是模板。如果它是一个模板,则宿主类可能不知道实例化参数化策略类所需的最小类型参数数量。如果策略类不是模板,则它可能无法作为策略类参与。这种情况与工厂方法(GoF)模式非常类似,在这种模式中,要创建的对象的类型事先未知。

template <class Apolicy>
class Host
{
  Apolicy direct_policy_use;
  Apolicy <SomeInternalType> InternalClone;  // Problem 1: Can't do this
};

template <class T, template <class T> class Apolicy>
class Host2
{
  Apolicy <T> common_use;  
  Apolicy <SomeInternalType> InternalClone;  
  // Can do this now but 
  // Problem 2: policies that require more than one type parameter can't participate.
};

解决方案和示例代码

[编辑 | 编辑源代码]

使用成员模板结构(称为 rebind)将不同的类型参数传递给策略类模板。例如,

template <typename T>
class NiftyAlloc
{
  public:
    template <typename Other>
    struct rebind // The Policy Clone idiom
    { 
       typedef NiftyAlloc <Other> other;
    };
    //...
};

template <typename T, class Alloc = NiftyAlloc <T> >
class Vector 
{
  public:
    typedef typename Alloc::template rebind<long>::other ClonePolicy;
    // Here, Alloc may not be a template class or a parametrized instantiation of
    // a class that takes unknown number of type parameters.
};

这里,Container 模板需要一个它实例化的分配策略的副本。因此,它使用 NiftyAlloc 策略公开的 rebind 机制。类型 Alloc::template rebind<long>::other 等同于 NiftyAlloc<long>。本质上,它表示:“我不知道此类型是什么类型的分配器,也不知道它分配什么,但我想要一个与它相同的分配器,它分配长整型。” 使用概念(它已从 C++0x 中删除),Vector 类可以编写类型概念,用于检查 Alloc 策略类型是否支持 rebind 概念。

为了让编译器满意,我们必须在 ClonePolicy typedef 中同时使用关键字 typename 和 template。规则如下:如果成员模板特化的名称出现在 .、-> 或 :: 运算符之后,并且该名称具有显式限定的模板参数,则在成员模板名称之前添加关键字 template。在 typedef 中也需要关键字 typename,因为 "other" 是一个类型,而不是一个变量。

已知用途

[编辑 | 编辑源代码]
  • 标准模板库
  • 不支持模板模板参数的编译器
[编辑 | 编辑源代码]

元函数包装器惯用法 比策略克隆更强大。策略克隆惯用法以比元函数包装器更抽象的方式指明其目的。rebind 模板本质上是元函数包装器。

参考资料

[编辑 | 编辑源代码]
华夏公益教科书