Boost C++ 库

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

创建概念检查类 - Boost C++ 函数库

创建概念检查类

作为如何创建概念检查类模板的示例,我们将介绍如何为 InputIterator(输入迭代器)概念创建相应的检查。完整定义请参考此处。

template <class X>
struct InputIterator
  : Assignable<X>, EqualityComparable<X>
{
 private:
    typedef std::iterator_traits<X> t;
 public:
    typedef typename t::value_type value_type;
    typedef typename t::difference_type difference_type;
    typedef typename t::reference reference;
    typedef typename t::pointer pointer;
    typedef typename t::iterator_category iterator_category;

    BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
    BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));
        
    BOOST_CONCEPT_USAGE(InputIterator)
    {
        X j(i);             // require copy construction
        same_type(*i++,v);  // require postincrement-dereference returning value_type
        X& x = ++j;         // require preincrement returning X&
    }
    
 private:
    X i;
    value_type v;

    // Type deduction will fail unless the arguments have the same type.
    template <typename T>
    void same_type(T const&, T const&);
};

演练

首先,按照惯例,我们以概念本身的名称来命名概念检查类。接下来,由于 InputIterator 是 Assignable(可赋值)和 EqualityComparable(可相等比较)的精化,我们从这些概念的检查类派生出其概念检查类。每当库检查 InputIterator 概念时,它都会自动检查是否符合 Assignable 和 EqualityComparable。

接着,我们将该概念的关联类型声明为成员 typedef。关联的差异类型(difference type)被要求为有符号整数,且迭代器类别必须可转换为 std::input_iterator_tag,因此我们对这些关系进行了断言。通过概念检查模板访问关联类型的语法,反映了 C++0x 中提议的关联类型访问语法。最后,我们使用 BOOST_CONCEPT_USAGE 宏来声明执行该概念所有有效表达式的函数。请注意,在这一点上,有时可能需要发挥一点创造力:例如,为了检查 *i++ 是否返回迭代器的值类型,我们将两个值传递给 same_type 成员函数模板,该模板要求两个参数具有相同的类型(忽略引用和 cv 限定符)。这虽然不是完美的检查,但总比没有好。

用于用法模式的值应作为数据成员

你可能想知道为什么我们在上面的示例中将 iv 声明为数据成员。为什么我们不简单地写成下面这样呢?

BOOST_CONCEPT_USAGE(InputIterator)
{
    X i;                // create the values we need
    value_type v;

    X j(i);             // require copy construction
    same_type(*i++,v);  // require postincrement-dereference returning value_type
    X& x = ++j;         // require preincrement returning X&
}

不幸的是,那样写代码效果并不理想,因为它无意中强加了一个要求,即 X 及其值类型都必须是可默认构造的。另一方面,由于 InputIterator 模板的实例永远不会被构造,编译器永远不需要检查其数据成员是如何构造的(C++ 标准第 14.7.1 节第 9 条)。因此,你应该始终将用法模式所需的值声明为数据成员

这类概念定义中的错误可以通过使用概念原型 (Concept Archetypes) 来检测,但最好还是在编写时就避免它们。

与提议的 C++0x 概念语言支持的相似性

该库在概念精化和关联类型访问方面的语法,反映了 C++0x 中相应的提议语法。然而,C++0x 将使用“签名 (signatures)”而不是用法模式来描述参与概念的类型的有效操作,因此在将你的概念检查类转换为语言支持的概念时,你需要将你的用法函数转换为一系列签名。

下一步:概念覆盖与原型
上一步:使用概念检查

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