Boost C++ 库

……是世界上备受推崇且设计精湛的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ Coding Standards

概念检查实现 - Boost C++ 函数库

警告

本文档已过时;现在使用类似但更新的实现技术。本文档还引用了库旧接口中的组件和协议,例如 BOOST_CLASS_REQUIRESconstraints() 函数,这些仍然受支持但已被弃用。

实现

理想情况下,我们希望在实例化时捕获并指示概念违规。如 D&E[2] 中所述,可以通过执行函数模板所需的所有要求来捕获错误。确切地如何执行这些要求(特别是有效表达式)是一个棘手的问题,因为我们希望代码被编译,但不执行。我们的方法是在一个分配给函数指针的独立函数中执行要求。在这种情况下,编译器会实例化函数,但不会实际调用它。此外,优化编译器会将指针赋值视为“死代码”(尽管在任何情况下,赋值添加的运行时开销都可以忽略不计)。理论上,编译器可能会跳过约束函数的语义分析和编译,这将使我们的函数指针技术无效。但是,这种情况不太可能发生,因为删除不必要的代码和函数通常是在编译器的后期阶段进行的。我们已成功地将函数指针技术与 GNU C++、Microsoft Visual C++ 以及几个基于 EDG 的编译器(KAI C++、SGI MIPSpro)一起使用。以下代码展示了如何将此技术应用于std::stable_sort()函数

  template <class RandomAccessIterator>
  void stable_sort_constraints(RandomAccessIterator i)
  {
    typename std::iterator_traits<RandomAccessIterator>
      ::difference_type n;
    i += n;  // exercise the requirements for RandomAccessIterator
    ...
  }
  template <class RandomAccessIterator>
  void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
  {
    typedef void (*fptr_type)(RandomAccessIterator);
    fptr_type x = &stable_sort_constraints;
    ...
  }

通常有一大堆要求需要检查,对于库实现者来说,为每个公共函数编写约束函数,如stable_sort_constraints()将很麻烦。相反,我们根据相应概念的定义将一组有效表达式分组。对于每个概念,我们定义一个概念检查类模板,其中模板参数是待检查的类型。该类包含一个constraints()成员函数,该函数执行概念的所有有效表达式。约束函数中使用的对象,例如nandi,被声明为概念检查类的数据成员。

  template <class Iter>
  struct RandomAccessIteratorConcept
  {
    void constraints()
    {
      i += n;
      ...
    }
    typename std::iterator_traits<RandomAccessIterator>
      ::difference_type n;
    Iter i;
    ...
  };

我们仍然可以使用函数指针机制来触发约束函数的实例化,但现在它将是成员函数指针。为了方便库实现者调用概念检查,我们将成员函数指针机制封装在一个名为function_requires()的函数中。以下代码片段展示了如何使用function_requires()来确保迭代器是一个 RandomAccessIterator

  template <class Iter>
  void stable_sort(Iter first, Iter last)
  {
    function_requires< RandomAccessIteratorConcept<Iter> >();
    ...
  }

定义function_requires()如下。该概念是已用建模类型实例化的概念检查类。我们将约束成员函数的地址分配给函数指针x,这会导致约束函数被实例化并检查概念的有效表达式。然后,我们将xx赋值以避免未使用的变量编译器警告,并将所有内容包装在一个 do-while 循环中以防止名称冲突。

  template <class Concept>
  void function_requires()
  {
    void (Concept::*x)() = BOOST_FPTR Concept::constraints;
    ignore_unused_variable_warning(x);
  }

为了检查类模板的类型参数,我们提供了BOOST_CLASS_REQUIRE宏,该宏可以在类定义的主体中使用(而function_requires()只能在函数主体中使用)。此宏声明一个嵌套的类模板,其中模板参数是函数指针。然后,我们在 typedef 中使用嵌套类类型,并将约束函数的函数指针类型作为模板参数。我们使用type_varand概念名称在嵌套类和 typedef 名称中,以帮助防止名称冲突。

#define BOOST_CLASS_REQUIRE(type_var, ns, concept) \
  typedef void (ns::concept <type_var>::* func##type_var##concept)(); \
  template <func##type_var##concept _Tp1> \
  struct concept_checking_##type_var##concept { }; \
  typedef concept_checking_##type_var##concept< \
    BOOST_FPTR ns::concept<type_var>::constraints> \
    concept_checking_typedef_##type_var##concept

此外,还有一些版本的BOOST_CLASS_REQUIRE接受更多参数,以处理涉及两个或多个类型之间交互的概念。BOOST_CLASS_REQUIRE在 BCCL 概念检查的实现中没有使用,因为某些编译器不实现函数指针类型的模板参数。

下一个:参考
上一个:使用概念进行编程

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