Boost C++ 库

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

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

Boost Concept Check Library (BCCL)

Concept Check 库允许以 提议的 C++ 语言扩展 的风格,为 概念 添加显式的声明和检查。

纲要

C++ 中的泛型编程以使用模板参数来表示抽象数据类型(或“概念”)为特征。然而,C++ 语言本身并未提供机制供类或函数模板的编写者显式声明用户提供的模板参数应建模(或遵循)的概念。模板参数通常以它们需要建模的概念命名,以向用户提示,并使概念要求在代码中显式化。但是,编译器不会特别对待这些名称:名为 RandomAccessIterator 的参数与名为 T 的参数对编译器而言没有区别。此外,

Boost Concept Checking Library 提供了

这些机制使用标准 C++,不会引入运行时开销。使用该机制的主要成本在于编译时间。

每一个编写类或函数模板的程序员都应该将概念检查作为其代码编写例程的常规部分。 应该为组件的公共接口中的每个模板参数插入概念检查。如果该概念是标准库中的概念之一,则只需使用 BCCL 中匹配的概念检查类即可。如果不是,则编写一个新的概念检查类 - 毕竟,它们通常只有几行长。对于新概念,还应该创建一个匹配的原型类,它是概念的最小骨架实现。

文档分为以下几个部分。

  1. 介绍
  2. 示例
  3. 历史
  4. 出版物
  5. 致谢
  6. 使用概念检查
  7. 创建概念检查类
  8. 概念覆盖和原型
  9. 使用概念编程
  10. 实现
  11. 参考

Jeremy Siek 贡献了此库。 Beman Dawes 管理了正式评审。 Dave Abrahams 贡献了重写,更新了语法以使其与 C++ 核心语言中概念支持的提议语法更兼容。

介绍

概念 是一组要求(有效表达式、关联类型、语义不变量、复杂性保证等),类型必须满足这些要求才能正确地用作泛型算法调用中的参数。在 C++ 中,概念由函数模板(泛型算法)的形式模板参数表示。然而,C++ 没有显式的表示概念的机制——模板参数只是占位符。根据惯例,这些参数的名称对应于所需的概念,但 C++ 编译器在模板参数绑定到实际类型时并不强制遵守概念。

自然,如果泛型算法使用不满足概念至少是语法要求的类型来调用,就会发生编译时错误。然而,这个错误本身并不能反映类型不满足概念的所有要求。相反,错误可能发生在实例化层次结构的深处,在那里某个表达式对该类型无效,或者某个假定的关联类型不可用。由此产生的错误消息很大程度上是信息不足的,并且基本是不可理解的。

需要一种机制在(或接近)实例化点强制执行“概念安全性”。Boost Concept Checking Library 使用了一些标准的 C++ 构造来强制早期概念合规性,并在不合规时提供更具信息量的错误消息。

请注意,此技术仅处理概念的语法要求(有效表达式和关联类型)。我们不处理语义不变量或复杂性保证,它们也是概念要求的一部分。

示例

我们举一个简单的例子来说明模板库的错误使用以及由此产生的错误消息。在下面的代码中,Standard Template Library (STL) [ 3, 4, 5 ] 中的泛型std::stable_sort()算法应用于链表。

  bad_error_eg.cpp:
1 #include <vector>
2 #include <complex>
3 #include <algorithm>
4 
5 int main()
6 {
7     std::vector<std::complex<float> > v;
8     std::stable_sort(v.begin(), v.end());
9 }

此处,std::stable_sort()算法的原型如下

  template <class RandomAccessIterator>
  void stable_sort(RandomAccessIterator first, RandomAccessIterator last);

使用 Gnu C++ 编译此代码会产生以下编译器错误

/usr/include/c++/4.1.2/bits/stl_algo.h: In function ‘void std::
  __insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with 
  _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float
  >*, std::vector<std::complex<float>, std::allocator<std::complex<
  float> > > >]’:
/usr/include/c++/4.1.2/bits/stl_algo.h:3066:   instantiated from ‘void 
  std::__inplace_stable_sort(_RandomAccessIterator, 
  _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::
  __normal_iterator<std::complex<float>*, std::vector<std::complex<
  float>, std::allocator<std::complex<float> > > >]’
/usr/include/c++/4.1.2/bits/stl_algo.h:3776:   instantiated from ‘void 
  std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with 
  _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float
  >*, std::vector<std::complex<float>, std::allocator<std::complex<
  float> > > >]’
bad_error_eg.cpp:8:   instantiated from here
/usr/include/c++/4.1.2/bits/stl_algo.h:2277: error: no match for 
  ‘operator<’ in ‘__val < __first. __gnu_cxx::__normal_iterator<
  _Iterator, _Container>::operator* [with _Iterator = std::complex<float
  >*, _Container = std::vector<std::complex<float>, std::allocator<
  std::complex<float> > >]()’

在这种情况下,根本错误是std:complex<float>不建模 LessThanComparable 概念。不幸的是,错误消息中没有任何内容向用户表明这一点。

对于有足够经验的 C++ 程序员来说,这个错误可能很明显,但是对于新手来说,有几个原因使得这个消息难以理解

  1. 错误消息与文档化的要求之间没有任何文本关联std::stable_sort()以及 LessThanComparable
  2. 错误消息过长,列出了 STL 内部的函数(例如 __insertion_sort),而用户不(也不应该!)知道或关心这些函数。
  3. 错误消息中列出了如此多的内部库函数,程序员很容易推断问题出在库中,而不是自己的代码中。

以下是我们期望从更具信息量的消息中获得的内容(实际上 Boost Concept Checking Library 产生的也是如此)

boost/concept_check.hpp: In destructor ‘boost::LessThanComparable<TT>::~
  LessThanComparable() [with TT = std::complex<float>]’:
boost/concept/detail/general.hpp:29:   instantiated from ‘static void boost::
  concepts::requirement<Model>::failed() [with Model = boost::
  LessThanComparable<std::complex<float> >]’
boost/concept/requires.hpp:30:   instantiated from ‘boost::_requires_<void
  (*)(boost::LessThanComparable<std::complex<float> >)>’
bad_error_eg.cpp:8:   instantiated from here
boost/concept_check.hpp:236: error: no match for ‘operator<’ in ‘((boost::
  LessThanComparable<std::complex<float> >*)this)->boost::
  LessThanComparable<std::complex<float> >::a < ((boost::
  LessThanComparable<std::complex<float> >*)this)->boost::
  LessThanComparable<std::complex<float> >::b’

此消息纠正了标准错误消息的几处不足。

历史

这个概念检查系统的第一个版本是由 Jeremy Siek 在 SGI 的 C++ 编译器和库小组工作时开发的。该版本现已成为 SGI STL 发行版的一部分。最初作为 boost concept checking library 引入的系统与 SGI STL 中的概念检查不同,因为概念检查类的定义大大简化了,但错误消息中的描述性文字较少。2006 年,该系统由 Dave Abrahams 重写(保持向后兼容),以便更易于使用,更类似于 C++ 核心语言中概念支持的提议,并提供更好的错误消息。

出版物

致谢

使用函数指针引起实例化的想法归功于 Alexander Stepanov。我们不确定使用表达式进行模板预检查的想法的起源,但它确实出现在 D&E[ 2 ] 中。感谢 Matt Austern 对 STL 概念的出色文档和组织,这些概念检查基于此。感谢 Boost 成员提出的宝贵意见和评论。

下一节:使用概念检查

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