C++ Boost

Creating Concept Checking Classes

As an example of how to create a concept checking class, we look at how to create the corresponding checks for the RandomAccessIterator concept. First, as a convention we name the concept checking class after the concept, and add the suffix ``Concept''. Next we must define a member function named constraints() in which we will exercise the valid expressions of the concept. function_requires() expects this function's signature to appear exactly as it is appears below: a void non-const member function with no parameters.

The first part of the constraints() function includes the requirements that correspond to the refinement relationship between RandomAccessIterator and the concepts which it builds upon: BidirectionalIterator and LessThanComparable. We could have instead used BOOST_CLASS_REQUIRE and placed these requirements in the class body, however BOOST_CLASS_REQUIRE uses C++ language features that are less portable.

Next we check that the iterator_category of the iterator is either std::random_access_iterator_tag or a derived class. After that we write out some code that corresponds to the valid expressions of the RandomAccessIterator concept. Typedefs can also be added to enforce the associated types of the concept.

  template <class Iter>
  struct RandomAccessIterator_concept
  {
    void constraints() {
      function_requires< BidirectionalIteratorConcept<Iter> >();
      function_requires< LessThanComparableConcept<Iter> >();
      function_requires< ConvertibleConcept<
        typename std::iterator_traits<Iter>::iterator_category,
        std::random_access_iterator_tag> >();

      i += n;
      i = i + n; i = n + i;
      i -= n;
      i = i - n;
      n = i - j;
      i[n];
    }
    Iter i, j;
    typename std::iterator_traits<Iter>::difference_type n;
  };
}
One potential pitfall in designing concept checking classes is using more expressions in the constraint function than necessary. For example, it is easy to accidentally use the default constructor to create the objects that will be needed in the expressions (and not all concepts require a default constructor). This is the reason we write the constraint function as a member function of a class. The objects involved in the expressions are declared as data members of the class. Since objects of the constraints class template are never instantiated, the default constructor for the concept checking class is never instantiated. Hence the data member's default constructors are never instantiated (C++ Standard Section 14.7.1 9).

Next: Concept Covering and Archetypes
Prev: Using Concept Checks


Copyright © 2000 Jeremy Siek([email protected]) Andrew Lumsdaine([email protected])