Generic programming in C++ is characterized by the use of template parameters to represent abstract data types (or ``concepts''). However, the C++ language itself does not provide a mechanism for the writer of a class or function template to explicitly state what concept the user-supplied template argument should model (or conform to). The common practice is to name the template parameter after the required concept as a hint to the user and to state the concept requirements in the documentation. However, often times the requirements are vague, incorrect, or nonexistent, which is quite a problem for the user, since he or she will not know exactly what kind of input is expected by the template. Furthermore, the following problems occur:
Any programmer writing class or function templates ought to make concept checking a normal part of their code writing routine. A concept check should be inserted for each template parameter in a component's public interface. If the concept is one of the ones from the Standard Library, then simply use the matching concept checking class in the BCCL. If not, then write a new concept checking class - after all, they are typically only a few lines long. For new concepts, a matching archetype class should also be created, which is a minimal skeleton-implementation of the concept
The documentation is organized into the following sections.
Jeremy Siek contributed this library. Beman Dawes managed the formal review.
Naturally, if a generic algorithm is invoked with a type that does not fulfill at least the syntactic requirements of the concept, a compile-time error will occur. However, this error will not per se reflect the fact that the type did not meet all of the requirements of the concept. Rather, the error may occur deep inside the instantiation hierarchy at the point where an expression is not valid for the type, or where a presumed associated type is not available. The resulting error messages are largely uninformative and basically impenetrable.
What is required is a mechanism for enforcing ``concept safety'' at (or close to) the point of instantiation. The Boost Concept Checking Library uses some standard C++ constructs to enforce early concept compliance and that provides more informative error messages upon non-compliance.
Note that this technique only addresses the syntactic requirements of concepts (the valid expressions and associated types). We do not address the semantic invariants or complexity guarantees, which are also part of concept requirements..
bad_error_eg.cpp: 1 #include <list> 2 #include <algorithm> 3 4 int main(int, char*[]) { 5 std::list<int> v; 6 std::stable_sort(v.begin(), v.end()); 7 return 0; 8 }Here, the std::stable_sort() algorithm is prototyped as follows:
template <class RandomAccessIterator> void stable_sort(RandomAccessIterator first, RandomAccessIterator last);Attempting to compile this code with Gnu C++ produces the following compiler error. The output from other compilers is listed in the Appendix.
stl_algo.h: In function `void __merge_sort_loop<_List_iterator <int,int &,int *>, int *, int>(_List_iterator<int,int &,int *>, _List_iterator<int,int &,int *>, int *, int)': stl_algo.h:1448: instantiated from `__merge_sort_with_buffer <_List_iterator<int,int &,int *>, int *, int>( _List_iterator<int,int &,int *>, _List_iterator<int,int &,int *>, int *, int *)' stl_algo.h:1485: instantiated from `__stable_sort_adaptive< _List_iterator<int,int &,int *>, int *, int>(_List_iterator <int,int &,int *>, _List_iterator<int,int &,int *>, int *, int)' stl_algo.h:1524: instantiated from here stl_algo.h:1377: no match for `_List_iterator<int,int &,int *> & - _List_iterator<int,int &,int *> &'In this case, the fundamental error is that std:list::iterator does not model the concept of RandomAccessIterator. The list iterator is only bidirectional, not fully random access (as would be a vector iterator). Unfortunately, there is nothing in the error message to indicate this to the user.
To a C++ programmer having enough experience with template libraries the error may be obvious. However, for the uninitiated, there are several reasons why this message would be hard to understand.
boost/concept_check.hpp: In method `void LessThanComparableConcept <_List_iterator<int,int &,int *> >::constraints()': boost/concept_check.hpp:334: instantiated from `RandomAccessIteratorConcept <_List_iterator<int,int &,int *> >::constraints()' bad_error_eg.cpp:6: instantiated from `stable_sort<_List_iterator <int,int &,int *> >(_List_iterator<int,int &,int *>, _List_iterator<int,int &,int *>)' boost/concept_check.hpp:209: no match for `_List_iterator<int,int &,int *> & < _List_iterator<int,int &,int *> &'This message rectifies several of the shortcomings of the standard error messages.
Copyright © 2000 | Jeremy Siek(jsiek@osl.iu.edu) Andrew Lumsdaine(lums@osl.iu.edu) |