作为如何创建概念检查类模板的示例,我们将介绍如何为 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 限定符)。这虽然不是完美的检查,但总比没有好。
你可能想知道为什么我们在上面的示例中将 i 和 v 声明为数据成员。为什么我们不简单地写成下面这样呢?
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 将使用“签名 (signatures)”而不是用法模式来描述参与概念的类型的有效操作,因此在将你的概念检查类转换为语言支持的概念时,你需要将你的用法函数转换为一系列签名。
| 版权 © 2000 | Jeremy Siek(jsiek@osl.iu.edu) Andrew Lumsdaine(lums@osl.iu.edu), 2007 David Abrahams. |