C++ Boost

Boost 概念檢查庫 (BCCL)

概念檢查庫可以讓你為符合 被 提議為C++語言擴展的 風格的 概 念 增加顯式的聲明和檢查。

Synopsis 概要

C++中的泛型編程的特點在於,使用模板參數來表示抽像數據類型(或稱“概 念”)。但是,C++語言本身本不提供機制讓類模板或函數模板的作者明確地指定用戶使用的模板參數必須遵循(或 符合)哪些概念。通常的做法是,在模板參數的取名上給用戶一些提示,並在代碼中明確給出這些概念的要求。但是,編譯器並不會特殊對待這些特殊的名字:一個 名為 RandomAccessIterator 的參數對於編譯器而言,與名為 T 的參數並無不同。而且:

Boost概念檢查庫可以提供:

以上機制使用標準C++,並且沒有運行期的代價。該機制的主要代價在於編譯期。

任何編寫類模板或函數模板的程序員都 應該將概念檢查作為他們所編寫的代碼的正常部分。概念檢查可以作為公有接口插入到每個模板參數中。如果該概念來自於標準庫,那 麼只要使用BCCL中相應的概念檢查類就可以了。如果不是,則需要編寫一個新的概念檢查類 - 畢竟只需要幾行代碼。對於新的概念,還應該創建一個相應的原型類,作為該概念的一個最小的基本實現。

本文檔按以下章節組織:

  1. Introduction 簡介
  2. Motivating Example 例子
  3. History 歷史
  4. Publications 出版
  5. Acknowledgements 鳴謝
  6. Using Concept Checks 使用概念檢查
  7. Creating Concept Checking Classes 創建概念檢查類
  8. Concept Covering and Archetypes 概念的充分性和原型
  9. Programming With Concepts 以概念編程
  10. Implementation 實現
  11. Reference 參考

Jeremy Siek 貢獻了這個庫。Beman Dawes 負責管理正式審查。Dave Abrahams 重寫了代碼,新的語法更加兼容於支持概念的C++核心語言所建議的語法。

Introduction 簡介

concept概念是指類型必須符合的一組要求(有效表達式,相關類型,語義不變式,複雜度保 證等等),只有符合這些要求的類型才可以作為正確的參數用於泛型算法的調用。在C++中,概念表現為函數模板(泛型算法)的形參。但是,C++並沒有顯式 的機制來指定概念 --- 模板參數只不過是一些佔位符。按照慣例,這些參數的名字應該反映出相應需要遵循的概念,但C++編譯器並會某個模板參數綁定到一個真實類型時進行概念符合 性的檢查。

通常,使用一個類型來調用泛型算法時,如果該類型不滿足相應概念的最小語法要求,則將產生一個編譯期錯誤。但是,這個錯誤並不能真正反 映出該類型不滿足概念要求的事實。更有甚者,這個錯誤可能發生在模板實例化層次的深處,與使用該類型的表達式相距甚遠,或者是某個推斷出來的相關類型不可 用。這種情況得到的錯誤信息是沒有幫助和基本上無法理解的。

我們需要的是一種在實例化點(或附近)實現強制"概念安全"的機制。Boost概念檢查庫使用一些標準的C++結構來強制早期的概念符 合檢查,並在不符合時提供更有用的錯誤信息。

注意,這些技術只針對概念的語法要求(有效表達式和相關類型)。不能針對概念要求中的其它部分,如語義不變式或複雜度保證。

Motivating Example 例子

我們給出一個簡單的例子來舉例說明模板庫的錯誤使用及其產生的錯誤信息。以下面的代碼中,來自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概念檢查庫所產生的):

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::
concept::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’

以上信息糾正了標準錯誤信息中的幾處缺點:

History 歷史

這個概念檢查系統的第一個版本是由 Jeremy Siek 在 SGI 工作時開發的,使用它們的 C++ 編譯器和庫。那個版本現在成為了 SGI STL 發佈版的組成部分。原先的 boost 概念檢查庫系統與 SGI STL 中的概念檢查有所不同,概念檢查類的定義得到了極大的簡化,其代價是在錯誤提示中有用的信息少了。在2006年,該系統由 Dave Abrahams 重寫(保留了向後兼容性),變得更易於使用,與C++核心語言所建議的概念支持更為相似,以及可以得到更好的錯誤信息。

Publications 出版

Acknowledgements 鳴謝

The idea to use function pointers to cause instantiation is due to Alexander Stepanov. We are not sure of the origin of the idea to use expressions to do up-front checking of templates, but it did appear in D&E[ 2]. Thanks to Matt Austern for his excellent documentation and organization of the STL concepts, upon which these concept checks are based. Thanks to Boost members for helpful comments and reviews.

Next: Using Concept Checks 使用概念檢查


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