C++ Boost

Using Concept Checks

For each concept there is a concept checking class which can be used to make sure that a given type (or set of types) models the concept. The Boost Concept Checking Library (BCCL) includes concept checking classes for all of the concepts used in the C++ standard library and a few more. The Reference section lists these concept checking classes. In addition, other boost libraries come with concept checking classes for the concepts that are particular to those libraries. For example, there are graph concepts and property map concepts. Also, whenever anyone writing a class of function template needs to express requirements that are not yet stated by an existing concept, a new concept checking class should be created. How to do this is explained in Creating Concept Checking Classes.

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.

function_requires()

The function_requires() function can be used in function bodies and the BOOST_CLASS_REQUIRE macro can be used inside class bodies. The function_requires() function takes no arguments, but has a template parameter for the concept checking class. This means that the instantiated concept checking class must be given as an explicit template argument, as shown below.
  // 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;
  }

BOOST_CLASS_REQUIRE

The BOOST_CLASS_REQUIRE macro can be used inside a class definition to check whether some type models a concept.
  // 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;
  }

Example

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])