Boost C++ 库

……世界上最受推崇且设计最专业的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu,《C++ 编码规范

概念覆盖与原型类 - Boost C++ 函数库

概念覆盖与原型类

我们已经讨论了为组件输入选择最小需求(概念)的重要性,但同样重要的是要验证所选的概念是否覆盖了算法。也就是说,任何可能的用户错误都应被概念检查所捕获,而不应被遗漏。概念覆盖率可以通过使用原型类(archetype classes)来验证。原型类是与特定概念关联的接口的精确实现。原型类的运行时行为并不重要,函数体可以留空。然后,可以使用这些原型类作为组件的输入来编译一个简单的测试程序。如果程序能够编译通过,就可以确定这些概念覆盖了该组件。以下代码展示了 输入迭代器(Input Iterator) 概念的原型类。必须格外小心,以确保原型与概念完全匹配。例如,该概念声明其返回类型operator*()必须可转换为值类型。它并未说明必须满足更严格的要求,即返回类型必须为T&const T&。这意味着如果使用T&const T&作为原型类的返回类型将是一个错误。正确的方法是创建一个人工的返回类型,使其可转换为T,就像我们在这里所做的那样,使用reference。原型类测试的有效性完全取决于它是否与概念完全匹配,这必须通过仔细的(人工)检查来验证。

template <class T>
class input_iterator_archetype
{
private:
  typedef input_iterator_archetype self;
public:
  typedef std::input_iterator_tag iterator_category;
  typedef T value_type;
  struct reference {
    operator const value_type&() const { return static_object<T>::get(); }
  };
  typedef const T* pointer;
  typedef std::ptrdiff_t difference_type;
  self& operator=(const self&) { return *this;  }
  bool operator==(const self&) const { return true; }
  bool operator!=(const self&) const { return true; }
  reference operator*() const { return reference(); }
  self& operator++() { return *this; }
  self operator++(int) { return *this; }
};

泛型算法通常通过实例化多种常见的输入类型来进行测试。例如,人们可能会应用std::stable_sort()并以基本指针类型作为迭代器。虽然这适用于测试算法的运行时行为,但对于确保概念覆盖率并没有帮助,因为 C++ 类型从不完全匹配特定的概念。相反,它们往往比任何单一概念所需的最小功能提供得更多。即使函数模板具有概念检查,并且能与给定类型一起编译通过,这些检查仍可能不足以覆盖实际使用的所有功能。这就是除了使用常见输入类型进行测试外,还要使用原型类进行编译非常重要的原因。

以下是 stl_concept_covering.cpp 的节选,展示了如何使用原型类来检查 std::stable_sort() 的需求文档。在这种情况下,看起来 SGI STL 文档中遗漏了 可复制构造(CopyConstructible)可赋值(Assignable) 要求(尝试移除那些原型类看看)。Boost 原型类被设计为可以分层。在此示例中,迭代器的值类型由三个原型组成。在 原型类参考 中,名为Base的模板参数指明了可以使用分层原型范式的地方。

{
  typedef less_than_comparable_archetype< 
      sgi_assignable_archetype<> > ValueType;
  random_access_iterator_archetype<ValueType> ri;
  std::stable_sort(ri, ri);
}

下一节:使用概念进行编程
上一节:创建概念检查类

版权 © 2000 Jeremy Siek(jsiek@osl.iu.edu) Andrew Lumsdaine(lums@osl.iu.edu), 2007 David Abrahams.