概念检查库允许用户以概念的风格添加显式声明和检查,该风格类似于提议的 C++ 语言扩展。
C++ 中的泛型编程的特点是使用模板参数来表示抽象数据类型(或“概念”)。然而,C++ 语言本身并没有提供一种机制,让类或函数模板的编写者能够显式地声明用户提供的模板参数应该建模(或符合)的概念。模板参数通常以它们需要建模的概念命名,作为对用户的提示,并在代码中明确概念要求。然而,编译器并不会特殊对待这些特殊名称:名为 `RandomAccessIterator` 的参数与名为 `T` 的参数对编译器来说没有什么不同。此外,
Boost 概念检查库提供
这些机制使用标准 C++,并且不会引入运行时开销。使用该机制的主要成本在于编译时。
**每个编写类或函数模板的程序员都应该将概念检查作为代码编写例程的常规部分。** 应该为组件公共接口中的每个模板参数插入概念检查。如果概念是标准库中的一个,则只需使用 BCCL 中匹配的概念检查类。如果不是,则编写一个新的概念检查类——毕竟,它们通常只有几行代码。对于新的概念,还应该创建一个匹配的原型类,它是该概念的最小骨架实现。
文档分为以下几个部分。
Jeremy Siek 贡献了这个库。Beman Dawes 管理了正式审查。 Dave Abrahams 贡献了一个重写,更新了语法,使其与 C++ 核心语言提出的概念支持语法更加兼容。
概念是一组要求(有效的表达式、关联的类型、语义不变量、复杂性保证等),一个类型必须满足这些要求才能作为参数正确地用于调用泛型算法。在 C++ 中,概念由函数模板(泛型算法)的形式模板参数表示。然而,C++ 没有显式表示概念的机制——模板参数仅仅是占位符。按照惯例,这些参数的名称与所需的概念相对应,但是当模板参数绑定到实际类型时,C++ 编译器不会强制遵守该概念。
自然地,如果使用不满足概念至少语法要求的类型调用泛型算法,则会发生编译时错误。然而,这个错误本身并不能反映该类型没有满足概念的所有要求。相反,错误可能发生在实例化层次结构深处,在表达式对该类型无效或假定的关联类型不可用的地方。 resulting error messages are largely uninformative and basically impenetrable.
我们需要一种在实例化点(或接近实例化点)强制执行“概念安全”的机制。Boost 概念检查库使用一些标准的 C++ 结构来强制执行早期概念合规性,并在不合规时提供更具信息量的错误消息。
请注意,此技术仅解决概念的语法要求(有效的表达式和关联类型)。我们不处理语义不变量或复杂性保证,这些也是概念要求的一部分。
我们提供一个简单的示例来说明模板库的不正确使用以及由此产生的错误消息。在下面的代码中,泛型std::stable_sort()标准模板库 (STL)[3, 4,5] 中的算法应用于链表。
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++ 程序员来说,这个错误可能很明显,但是对于新手来说,这个消息可能很难理解,原因有几个
std::stable_sort()和 LessThanComparable 的文档化要求之间没有文本关联。
以下是我们可能期望从更具信息量的消息中得到的内容的示例(实际上是 Boost 概念检查库产生的内容)
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 概念检查库引入的系统与 SGI STL 中的概念检查不同之处在于,概念检查类的定义得到了极大的简化,代价是错误消息中的措辞不太有用。2006 年,Dave Abrahams 重写了该系统(保留了向后兼容性),使其更易于使用,更类似于 C++ 核心语言提出的概念支持,并提供更好的错误消息。
使用函数指针来导致实例化的想法来自 Alexander Stepanov。我们不确定使用表达式来预先检查模板的想法的起源,但它确实出现在 D&E[ 2] 中。感谢 Matt Austern 对 STL 概念的出色文档和组织,这些概念检查就是基于这些概念。感谢 Boost 成员的有益评论和审查。
版权所有 © 2000 | Jeremy Siek([email protected]) Andrew Lumsdaine([email protected]), 2007 David Abrahams。 |