An example of a concept checking class from the BCCL is the EqualityComparableConcept class. The class corresponds to the EqualityComparable requirements described in 20.1.1 of the C++ Standard, and to the EqualityComparable concept documented in the SGI STL.
template <class T> struct EqualityComparableConcept;The template argument T will the type to be checked. That is, the purpose of EqualityComparableConcept is to make sure that the template argument given for T models the EqualityComparable concept.
Each concept checking class has a member function named constraints() which contains the valid expressions for the concept. To check whether some type is EqualityComparable we need to instantiate the concept checking class with the type and then find a way to get the compiler to compile the constraints() function without actually executing the function. The Boost Concept Checking Library defines two utilities that make this easy: function_requires() and BOOST_CLASS_REQUIRE.
// In my library: template <class T> void generic_library_function(T x) { function_requires< EqualityComparableConcept<T> >(); // ... }; // In the user's code: class foo { //... }; int main() { foo f; generic_library_function(f); return 0; }
// In my library: template <class T> struct generic_library_class { BOOST_CLASS_REQUIRE(T, boost, EqualityComparableConcept); // ... }; // In the user's code: class foo { //... }; int main() { generic_library_class<foo> glc; // ... return 0; }
Getting back to the earlier motivating example, one good application of concept checks would be to insert function_requires() at the top of std::stable_sort() to make sure the template parameter type models RandomAccessIterator. In addition, std::stable_sort() requires that the value_type of the iterators be LessThanComparable, so we also use function_requires() to check this.
template <class RandomAccessIter> void stable_sort(RandomAccessIter first, RandomAccessIter last) { function_requires< RandomAccessIteratorConcept<RandomAccessIter> >(); typedef typename std::iterator_traits<RandomAccessIter>::value_type value_type; function_requires< LessThanComparableConcept<value_type> >(); ... }
Some concepts deal with more than one type. In this case the corresponding concept checking class will have multiple template parameters. The following example shows how function_requires() is used with the ReadWritePropertyMap concept which takes two type parameters: a property map and the key type for the map.
template <class IncidenceGraph, class Buffer, class BFSVisitor, class ColorMap> void breadth_first_search(IncidenceGraph& g, typename graph_traits<IncidenceGraph>::vertex_descriptor s, Buffer& Q, BFSVisitor vis, ColorMap color) { typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex; function_requires< ReadWritePropertyMap<ColorMap, Vertex> >(); ... }As an example of using BOOST_CLASS_REQUIRE we look at a concept check that could be added to std::vector. One requirement that is placed on the element type is that it must be Assignable. We can check this by inserting class_requires<AssignableConcept<T> > at the top of the definition for std::vector.
namespace std { template <class T> struct vector { BOOST_CLASS_REQUIRE(T, boost, AssignableConcept); ... }; }Although the concept checks are designed for use by generic library implementors, they can also be useful to end users. Sometimes one may not be sure whether some type models a particular concept. This can easily be checked by creating a small program and using function_requires() with the type and concept in question. The file stl_concept_checks.cpp gives and example of applying the concept checks to STL containers.
Prev: Concept Checking Introduction
Next: Creating Concept Checking Classes
Copyright © 2000 | Jeremy Siek([email protected]) Andrew Lumsdaine([email protected]) |