From 7dd50ca8f298ce8a86dd1c6a0ca3d5ea6670e6ba Mon Sep 17 00:00:00 2001
From: Dave Abrahams
-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:
+ 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 the concept that the user-supplied
+ template argument should model (or conform to). Template parameters are
+ commonly named after the concept they're required to model as a hint to the
+ user, and to make the concept requirements explicit in code. However, the
+ compiler doesn't treat these special names specially: a parameter named
+ The Boost Concept Checking Library provides:
- The mechanisms use standard C++ and introduce no run-time overhead.
+ The main cost of using the mechanism is in compile-time.
-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
+ Every 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.
+ 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..
+ Jeremy Siek contributed this
+ library. Beman Dawes managed
+ the formal review. Dave
+ Abrahams contributed a rewrite that updated syntax to be more
+ compatible with proposed syntax for concept support the C++ core
+ language. A
+ concept is a set of requirements (valid expressions, associated
+ types, semantic invariants, complexity guarantees, etc.) that a type must
+ fulfill to be correctly used as arguments in a call to a generic algorithm.
+ In C++, concepts are represented by formal template parameters to function
+ templates (generic algorithms). However, C++ has no explicit mechanism for
+ representing concepts—template parameters are merely placeholders. By
+ convention, these parameters are given names corresponding to the concept
+ that is required, but a C++ compiler does not enforce compliance to the
+ concept when the template parameter is bound to an actual type.
+
+ 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.. We present a simple example to illustrate incorrect usage of a template
+ library and the resulting error messages. In the code below, the generic
+ std::stable_sort() algorithm from the Standard Template Library
+ (STL)[3, 4,5] is applied to a linked
+ list. Here, the std::stable_sort() algorithm is prototyped as
+ follows: Attempting to compile this code with Gnu C++ produces the following
+ compiler error: In this case, the fundamental error is
+ that std:complex<float> does not model the LessThanComparable
+ concept. Unfortunately, there is nothing in the error message to
+ indicate that 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.
+ The error may be obvious to a C++ programmer having enough
+ experience with template libraries, but there are several reasons
+ why this message could be hard for the uninitiated to
+ understand: The following is an example of what we might expect from a more
+ informative message (and is in fact what the Boost Concept Checking Library
+ produces): This message rectifies several of the shortcomings of the standard error
+ messages. The first version of this concept checking system was developed
+ by Jeremy Siek while working at SGI in their C++ compiler and
+ library group. That version is now part of the SGI STL
+ distribution. The system originally introduced as the boost concept
+ checking library differs from concept checking in the SGI STL in
+ that the definition of concept checking classes was greatly
+ simplified, at the price of less helpful verbiage in the error
+ messages. In 2006 the system was rewritten (preserving backward
+ compatibility) by Dave Abrahams to be easier to use, more similar to
+ the proposed concept support the C++ core language, and to give
+ better error messages.
+ 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.
- We have discussed how it is important to select the minimal requirements
+ (concepts) for the inputs to a component, but it is equally important to
+ verify that the chosen concepts cover the algorithm. That is, any
+ possible user error should be caught by the concept checks and not let slip
+ through. Concept coverage can be verified through the use of archetype
+ classes. An archetype class is an exact implementation of the interface
+ associated with a particular concept. The run-time behavior of the
+ archetype class is not important, the functions can be left empty. A simple
+ test program can then be compiled with the archetype classes as the inputs
+ to the component. If the program compiles then one can be sure that the
+ concepts cover the component. The following code shows the archetype class
+ for the Input
+ Iterator concept. Some care must be taken to ensure that the archetype
+ is an exact match to the concept. For example, the concept states that the
+ return type of operator*() must be convertible to the value type.
+ It does not state the more stringent requirement that the return type be
+ T& or const T&. That means it would be a mistake
+ to use T& or const T& for the return type of the
+ archetype class. The correct approach is to create an artificial return
+ type that is convertible to T, as we have done here with
+ reference. The validity of the archetype class test is completely
+ dependent on it being an exact match with the concept, which must be
+ verified by careful (manual) inspection. Generic algorithms are often tested by being instantiated with a number
+ of common input types. For example, one might apply
+ std::stable_sort() with basic pointer types as the iterators.
+ Though appropriate for testing the run-time behavior of the algorithm, this
+ is not helpful for ensuring concept coverage because C++ types never match
+ particular concepts exactly. Instead, they often provide more than the
+ minimal functionality required by any one concept. Even though the function
+ template has concept checks, and compiles with a given type, the checks may
+ still fall short of covering all the functionality that is actually used.
+ This is why it is important to compile with archetype classes in addition
+ to testing with common input types.
-The following is an excerpt from stl_concept_covering.cpp
-that shows how archetypes can be used to check the requirement
-documentation for
-
-std::stable_sort(). In this case, it looks like the CopyConstructible and Assignable requirements were
-forgotten in the SGI STL documentation (try removing those
-archetypes). The Boost archetype classes have been designed so that
-they can be layered. In this example the value type of the iterator
-is composed out of three archetypes. In the archetype class reference
-below, template parameters named Base indicate where the
-layered archetype can be used.
-
- The following is an excerpt from stl_concept_covering.cpp that
+ shows how archetypes can be used to check the requirement documentation for
+ std::stable_sort().
+ In this case, it looks like the CopyConstructible and Assignable requirements were forgotten in
+ the SGI STL documentation (try removing those archetypes). The Boost
+ archetype classes have been designed so that they can be layered. In this
+ example the value type of the iterator is composed out of three archetypes.
+ In the archetype class
+ reference, template parameters named Base indicate where the
+ layered archetype paradigm can be used. Next: Programming with
+ Concepts
-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.
+ As an example of how to create a concept checking class template, we
+ look at how to create the corresponding checks for the InputIterator concept.
+ The complete definition is here: First, as a convention we name the concept checking class after the
+ concept. Next, since InputIterator is a refinement of Assignable and
+ EqualityComparable, we derive its concept checking class from the checking
+ classes for those other concepts. The library will automatically check for
+ conformance to Assignable and EqualityComparable whenever it checks the
+ InputIterator concept. Next, we declare the concept's associated types
+ as member typedefs. The associated difference type is required to be a
+ signed integer, and the iterator category has to be convertible to
+ std::input_iterator_tag, so we assert those relationships. The syntax for
+ accessing associated types through the concept-checking template mirrors
+ the proposed
+ syntax for associated type access in C++0x Finally, we use the
+ You may be wondering why we declared Unfortunately, that code wouldn't have worked out so well, because it
+ unintentionally imposes the requirement that
-Next: Concept Covering and Archetypes These sorts of errors in concept definitions can be detected by the use
+ of Concept Archetypes, but it's always
+ better to avoid them pre-emptively. This library's syntaxes for concept refinement and for access of
+ associated types mirrors the corresponding proposed
+ syntaxes in C++0x. However, C++0x will use
+ “signatures” rather than usage patterns to
+ describe the valid operations on types participating in a concept, so when
+ converting your concept checking classes into language-supported concepts,
+ you'll need to translate your usage function into a series of
+ signatures. Next: Concept Covering and
+ Archetypes This documentation is out-of-date; similar but
+ newer implementation techniques are now used. This documentation
+ also refers to components and protocols in the library's old
+ interace such as Ideally we would like to catch, and indicate, the concept violation at
+ the point of instantiation. As mentioned in D&E[2], the error can be
+ caught by exercising all of the requirements needed by the function
+ template. Exactly how the requirements (the valid expressions in
+ particular) are exercised is a tricky issue, since we want the code to be
+ compiled—but not executed. Our approach is to exercise the
+ requirements in a separate function that is assigned to a function pointer.
+ In this case, the compiler will instantiate the function but will not
+ actually invoke it. In addition, an optimizing compiler will remove the
+ pointer assignment as ``dead code'' (though the run-time overhead added by
+ the assignment would be trivial in any case). It might be conceivable for a
+ compiler to skip the semantic analysis and compilation of the constraints
+ function in the first place, which would make our function pointer
+ technique ineffective. However, this is unlikely because removal of
+ unnecessary code and functions is typically done in later stages of a
+ compiler. We have successfully used the function pointer technique with GNU
+ C++, Microsoft Visual C++, and several EDG-based compilers (KAI C++, SGI
+ MIPSpro). The following code shows how this technique can be applied to the
+ std::stable_sort() function: There is often a large set of requirements that need to be checked, and
+ it would be cumbersome for the library implementor to write constraint
+ functions like stable_sort_constraints() for every public
+ function. Instead, we group sets of valid expressions together, according
+ to the definitions of the corresponding concepts. For each concept we
+ define a concept checking class template where the template parameter is
+ for the type to be checked. The class contains a contraints()
+ member function which exercises all of the valid expressions of the
+ concept. The objects used in the constraints function, such as n
+ and i, are declared as data members of the concept checking
+ class. We can still use the function pointer mechanism to cause instantiation
+ of the constraints function, however now it will be a member function
+ pointer. To make it easy for the library implementor to invoke the concept
+ checks, we wrap the member function pointer mechanism in a function named
+ function_requires(). The following code snippet shows how to use
+ function_requires() to make sure that the iterator is a RandomAccessIterator. The definition of the function_requires() is as follows. The
+ Concept is the concept checking class that has been instantiated
+ with the modeling type. We assign the address of the constraints member
+ function to the function pointer x, which causes the instantiation
+ of the constraints function and checking of the concept's valid
+ expressions. We then assign x to x to avoid unused
+ variable compiler warnings, and wrap everything in a do-while loop to
+ prevent name collisions. To check the type parameters of class templates, we provide the
+ BOOST_CLASS_REQUIRE macro which can be used inside the body of a
+ class definition (whereas function_requires() can only be used
+ inside of a function body). This macro declares a nested class template,
+ where the template parameter is a function pointer. We then use the nested
+ class type in a typedef with the function pointer type of the constraint
+ function as the template argument. We use the type_var and
+ concept names in the nested class and typedef names to help
+ prevent name collisions.
-#include
+
+
-
+ The Boost Concept Check Library (BCCL)
-The Boost Concept Check Library (BCCL)
+
+ The Concept Check library allows one to add explicit statement and
+ checking of concepts in the style
+ of the proposed
+ C++ language extension.
+
-
-
-header
-boost/concept_check.hpp
-
+
and
-boost/concept_archetype.hpp
-Synopsis
-RandomAccessIterator
is no different to the compiler than one
+ named T
. Furthermore,
-
+
+
-
+
+
-
+
+
+
+ Introduction
-
-A concept is a set of requirements (valid expressions,
-associated types, semantic invariants, complexity guarantees, etc.)
-that a type must fulfill to be correctly used as arguments in a call
-to a generic algorithm. In C++, concepts are represented by formal
-template parameters to function templates (generic algorithms).
-However, C++ has no explicit mechanism for representing concepts ---
-template parameters are merely placeholders. By convention, these
-parameters are given names corresponding to the concept that is
-required, but a C++ compiler does not enforce compliance to the
-concept when the template parameter is bound to an actual type.
+ Motivating Example
+
+
Introduction
Motivating
+ Example
+
+
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 }
+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 }
-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 *> &'
+
+/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> > >]()’
-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.
+
-
+
+
+
+ __insertion_sort
) that the user
+ does not (and should not!) know or care about.
-boost/concept_check.hpp: In method `void LessThanComparableConcept
- <_List_iterator<int,int &,int *> >::~LessThanComparableConcept()':
-boost/concept_check.hpp:334: instantiated from `RandomAccessIteratorConcept
- <_List_iterator<int,int &,int *> >::~RandomAccessIteratorConcept()'
-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 *> &'
+
+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’
-This message rectifies several of the shortcomings of the standard
-error messages.
+
-
+
+
-History
+ std::stable_sort
.Publications
+ History
-
-
+ Acknowledgements
+ Publications
-The idea to use function pointers to cause instantiation is due to
-Alexander Stepanov. I am 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.
+
+
+ Acknowledgements
-
-
-
-
+
- Copyright © 2000
-Jeremy Siek(jsiek@osl.iu.edu)
-Andrew Lumsdaine(lums@osl.iu.edu)
-
+
+
+
diff --git a/concept_covering.htm b/concept_covering.htm
index dfadd60..96c3208 100644
--- a/concept_covering.htm
+++ b/concept_covering.htm
@@ -1,126 +1,125 @@
-
-
-
-
+
+ Copyright © 2000
-
-
+ Jeremy Siek(jsiek@osl.iu.edu) Andrew
+ Lumsdaine(lums@osl.iu.edu),
+ 2007 David Abrahams.
+
+
+
-
+
+
+
+
+
-Concept Covering and Archetypes
+
+
-We have discussed how it is important to select the minimal
-requirements (concepts) for the inputs to a component, but it is
-equally important to verify that the chosen concepts cover the
-algorithm. That is, any possible user error should be caught by the
-concept checks and not let slip through. Concept coverage can be
-verified through the use of archetype classes. An archetype
-class is an exact implementation of the interface associated with a
-particular concept. The run-time behavior of the archetype class is
-not important, the functions can be left empty. A simple test program
-can then be compiled with the archetype classes as the inputs to the
-component. If the program compiles then one can be sure that the
-concepts cover the component.
+
-
- template <class T>
- class input_iterator_archetype
- {
- private:
- typedef input_iterator_archetype self;
- public:
- typedef std::input_iterator_tag iterator_category;
- typedef T value_type;
- struct reference {
- operator const value_type&() const { return static_object<T>::get(); }
- };
- typedef const T* pointer;
- typedef std::ptrdiff_t difference_type;
- self& operator=(const self&) { return *this; }
- bool operator==(const self&) const { return true; }
- bool operator!=(const self&) const { return true; }
- reference operator*() const { return reference(); }
- self& operator++() { return *this; }
- self operator++(int) { return *this; }
+
Concept Covering and
+ Archetypes
+
+
+template <class T>
+class input_iterator_archetype
+{
+private:
+ typedef input_iterator_archetype self;
+public:
+ typedef std::input_iterator_tag iterator_category;
+ typedef T value_type;
+ struct reference {
+ operator const value_type&() const { return static_object<T>::get(); }
};
+ typedef const T* pointer;
+ typedef std::ptrdiff_t difference_type;
+ self& operator=(const self&) { return *this; }
+ bool operator==(const self&) const { return true; }
+ bool operator!=(const self&) const { return true; }
+ reference operator*() const { return reference(); }
+ self& operator++() { return *this; }
+ self operator++(int) { return *this; }
+};
-Generic algorithms are often tested by being instantiated with a
-number of common input types. For example, one might apply
-std::stable_sort() with basic pointer types as the iterators.
-Though appropriate for testing the run-time behavior of the algorithm,
-this is not helpful for ensuring concept coverage because C++ types
-never match particular concepts, they often provide much more than the
-minimal functionality required by any one concept. That is, even
-though the function template compiles with a given type, the concept
-requirements may still fall short of covering the functions actual
-requirements. This is why it is important to compile with archetype
-classes in addition to testing with common input types.
+
- {
- typedef less_than_comparable_archetype<
- sgi_assignable_archetype<> > ValueType;
- random_access_iterator_archetype<ValueType> ri;
- std::stable_sort(ri, ri);
- }
+
+{
+ typedef less_than_comparable_archetype<
+ sgi_assignable_archetype<> > ValueType;
+ random_access_iterator_archetype<ValueType> ri;
+ std::stable_sort(ri, ri);
+}
-Next: Programming with Concepts
-Prev: Creating Concept Checking Classes
+
+ Prev: Creating Concept Checking
+ Classes
+
-
-
-
-
+
- Copyright © 2000
-Jeremy Siek(jsiek@osl.iu.edu)
-Andrew Lumsdaine(lums@osl.iu.edu)
-
+
+
+
diff --git a/creating_concepts.htm b/creating_concepts.htm
index d19ca01..f6cca8f 100644
--- a/creating_concepts.htm
+++ b/creating_concepts.htm
@@ -1,110 +1,157 @@
-
-
-
-
+
+ Copyright © 2000
-
-
+ Jeremy Siek(jsiek@osl.iu.edu) Andrew
+ Lumsdaine(lums@osl.iu.edu),
+ 2007 David Abrahams.
+
+
-
+
+
+
+
+
+
+
+
-Creating Concept Checking Classes
+
-Creating
+ Concept Checking Classes
-
+template <class X>
+struct InputIterator
+ : Assignable<X>, EqualityComparable<X>
+{
+ private:
+ typedef std::iterator_traits<X> t;
+ public:
+ typedef typename t::value_type value_type;
+ typedef typename t::difference_type difference_type;
+ typedef typename t::reference reference;
+ typedef typename t::pointer pointer;
+ typedef typename t::iterator_category iterator_category;
-
- template <class Iter>
- struct RandomAccessIteratorConcept
- {
- 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];
+ BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
+ BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));
+
+ BOOST_CONCEPT_USAGE(InputIterator)
+ {
+ X j(i); // require copy construction
+ same_type(*i++,v); // require postincrement-dereference returning value_type
+ X& x = ++j; // require preincrement returning X&
}
- Iter i, j;
- typename std::iterator_traits<Iter>::difference_type n;
- };
+
+ private:
+ X i;
+ value_type v;
+
+ // Type deduction will fail unless the arguments have the same type.
+ template <typename T>
+ void same_type(T const&, T const&);
+};
+
+
+ Walkthrough
+
+ BOOST_CONCEPT_USAGE
macro to declare the function that
+ exercises all the concept's valid expressions. Note that at this point you
+ may sometimes need to be a little creative: for example, to check that
+ *i++
returns the iterator's value type, we pass both values to
+ the same_type
member function template, which requires both
+ arguments to have the same type, modulo references and cv-qualification.
+ It's an imperfect check, but it's better than nothing.Values for Usage Patterns Should Be Data Members
+
+ i
and v
+ as data members in the example above. Why didn't we simply write the
+ following?
+BOOST_CONCEPT_USAGE(InputIterator)
+{
+ X i; // create the values we need
+ value_type v;
+
+ X j(i); // require copy construction
+ same_type(*i++,v); // require postincrement-dereference returning value_type
+ X& x = ++j; // require preincrement returning X&
}
-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).
+ X
and its value
+ type are both default-constructible. On the other hand, since instances of
+ the InputIterator
template will never be constructed, the
+ compiler never has to check how its data members will be constructed (C++
+ Standard Section 14.7.1 9). For that reason you should always
+ declare values needed for usage patterns as data members.
-Prev: Using Concept Checks
+ Similarity to Proposed C++0x Language Support for Concepts
-
-
-
-
+
- Copyright © 2000
-Jeremy Siek(jsiek@osl.iu.edu)
-Andrew Lumsdaine(lums@osl.iu.edu)
-
+ Prev: Using Concept
+ Checks
+
+
+
+
+
diff --git a/fake_sort.hpp b/fake_sort.hpp
index bdac487..131bcc7 100755
--- a/fake_sort.hpp
+++ b/fake_sort.hpp
@@ -13,7 +13,7 @@ namespace fake
using namespace boost;
template
+
+ Copyright © 2000
+
+ Jeremy Siek(jsiek@osl.iu.edu) Andrew
+ Lumsdaine(lums@osl.iu.edu),
+ 2007 David Abrahams.
+
+
-
+
+
+
+
+
+
+
+
+
-Implementation
+
-
+
Warning
+
+ BOOST_CLASS_REQUIRES
+ and constraints()
functions, which are still supported
+ but deprecated.Implementation
+
+
template <class RandomAccessIterator>
void stable_sort_constraints(RandomAccessIterator i)
{
@@ -57,24 +66,23 @@ can be applied to the std::stable_sort() function:
void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
{
typedef void (*fptr_type)(RandomAccessIterator);
- fptr_type x = &stable_sort_constraints;
+ fptr_type x = &stable_sort_constraints;
...
}
-There is often a large set of requirements that need to be checked,
-and it would be cumbersome for the library implementor to write
-constraint functions like stable_sort_constraints() for every
-public function. Instead, we group sets of valid expressions
-together, according to the definitions of the corresponding concepts.
-For each concept we define a concept checking class template where the
-template parameter is for the type to be checked. The class contains
-a contraints() member function which exercises all of the
-valid expressions of the concept. The objects used in the constraints
-function, such as n and i, are declared as data
-members of the concept checking class.
-
-
+
template <class Iter>
struct RandomAccessIteratorConcept
{
@@ -90,18 +98,14 @@ members of the concept checking class.
};
-We can still use the function pointer mechanism to cause instantiation
-of the constraints function, however now it will be a member function
-pointer. To make it easy for the library implementor to invoke the
-concept checks, we wrap the member function pointer mechanism in a
-function named function_requires(). The following code
-snippet shows how to use function_requires() to make sure
-that the iterator is a
-
-RandomAccessIterator.
-
-
+
template <class Iter>
void stable_sort(Iter first, Iter last)
{
@@ -110,16 +114,15 @@ RandomAccessIterator.
}
-The definition of the function_requires() is as follows. The
-Concept is the concept checking class that has been
-instantiated with the modeling type. We assign the address of the
-constraints member function to the function pointer x, which
-causes the instantiation of the constraints function and checking of
-the concept's valid expressions. We then assign x to
-x to avoid unused variable compiler warnings, and wrap
-everything in a do-while loop to prevent name collisions.
-
-
+
template <class Concept>
void function_requires()
{
@@ -128,17 +131,16 @@ everything in a do-while loop to prevent name collisions.
}
-To check the type parameters of class templates, we provide the
-BOOST_CLASS_REQUIRE macro which can be used inside the body of a
-class definition (whereas function_requires() can only be used
-inside of a function body). This macro declares a nested class
-template, where the template parameter is a function pointer. We then
-use the nested class type in a typedef with the function pointer type
-of the constraint function as the template argument. We use the
-type_var and concept names in the nested class and
-typedef names to help prevent name collisions.
-
-
+
#define BOOST_CLASS_REQUIRE(type_var, ns, concept) \
typedef void (ns::concept <type_var>::* func##type_var##concept)(); \
template <func##type_var##concept _Tp1> \
@@ -148,14 +150,12 @@ typedef names to help prevent name collisions.
concept_checking_typedef_##type_var##concept
-In addition, there are versions of BOOST_CLASS_REQUIRE that
-take more arguments, to handle concepts that include interactions
-between two or more types. BOOST_CLASS_REQUIRE was not used
-in the implementation of the BCCL concept checks because some
-compilers do not implement template parameters of function pointer
-type.
-
-
+-->
-Next: Reference
-Prev: Programming With Concepts
+
Next: Reference
+ Prev: Programming With
+ Concepts
Copyright © 2000 | -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) - |
Copyright © 2000 | - - +Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. + |
-Requirement Minimization Principle: Minimize the requirements -on the input parameters of a component to increase its reusability. +
+-There is natural tension in this statement. By definition, the input -parameters must be used by the component in order for the component to -accomplish its task (by ``component'' we mean a function or class -template). The challenge then is to implement the component in such a -way that makes the fewest assumptions (the minimum requirements) about -the inputs while still accomplishing the task. +
-The traditional notions of abstraction tie in directly to the -idea of minimal requirements. The more abstract the input, the fewer -the requirements. Thus, concepts are simply the embodiment of generic -abstract data types in C++ template programming. +
The process of deciding how to group requirements into concepts and + deciding which concepts to use in each algorithm is perhaps the most + difficult (yet most important) part of building a generic library. A + guiding principle to use during this process is one we call the + requirement minimization principle.
--When designing the concepts for some problem domain it is important to -keep in mind their purpose, namely to express the requirements for the -input to the components. With respect to the requirement minimization -principle, this means we want to minimize concepts. +
Requirement Minimization Principle: Minimize the requirements on + the input parameters of a component to increase its reusability.
- +--> --Minimality in concepts is a property associated with the underlying -semantics of the problem domain being represented. In the problem -domain of basic containers, requiring traversal in a single direction -is a smaller requirement than requiring traversal in both directions -(hence the distinction between -ForwardIterator and - -BidirectionalIterator). The semantic difference can be easily seen -in the difference between the set of concrete data structures that -have forward iterators versus the set that has bidirectional -iterators. For example, singly-linked lists would fall in the set of -data structures having forward iterators, but not bidirectional -iterators. In addition, the set of algorithms that one can implement -using only forward iterators is quite different than the set that can -be implemented with bidirectional iterators. Because of this, it is -important to factor families of requirements into rather fine-grained -concepts. For example, the requirements for iterators are factored -into the six STL iterator concepts (trivial, output, input, forward, -bidirectional, and random access). +
Minimality in concepts is a property associated with the underlying + semantics of the problem domain being represented. In the problem domain of + basic containers, requiring traversal in a single direction is a smaller + requirement than requiring traversal in both directions (hence the + distinction between ForwardIterator and + BidirectionalIterator). + The semantic difference can be easily seen in the difference between the + set of concrete data structures that have forward iterators versus the set + that has bidirectional iterators. For example, singly-linked lists would + fall in the set of data structures having forward iterators, but not + bidirectional iterators. In addition, the set of algorithms that one can + implement using only forward iterators is quite different than the set that + can be implemented with bidirectional iterators. Because of this, it is + important to factor families of requirements into rather fine-grained + concepts. For example, the requirements for iterators are factored into the + six STL iterator concepts (trivial, output, input, forward, bidirectional, + and random access).
-
-Next: Implementation
-Prev: Concept Covering and Archetypes
+
Next: Implementation
+ Prev: Concept Covering and
+ Archetypes
Copyright © 2000 | -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) - |
Copyright © 2000 | - - +Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. + |
- template <class Concept> - void function_requires(); +Reference
+ ++
+ +- Macros
+ +- Basic Concept Checking Classes
+ +- Iterator Concept Checking + Classes
+ +- Function Object Concept Checking + Classes
+ +- Container Concept Checking + Classes
+ +- Basic Archetype Classes
+ +- Iterator Archetype Classes
+ +- Function Object Archetype + Classes
+ +- Container Archetype Classes
+ +- Deprecated Functions
+ +- Deprecated Macros
+ +- Deprecated Concept + Checking Classes
+Macros
++#include "boost/concept/assert.hpp" + +BOOST_CONCEPT_ASSERT((concept checking class template specialization));-Macros
+Effects: causes a compilation failure if the concept is + not satisfied.
-
+ Note: this macro can be used at global, class, or function + scope.- // Apply concept checks in class definitions. - BOOST_CLASS_REQUIRE(type, namespace-of-concept, concept); - BOOST_CLASS_REQUIRE2(type1, type2, namespace-of-concept, concept); - BOOST_CLASS_REQUIRE3(type1, type2, type3, namespace-of-concept, concept); - BOOST_CLASS_REQUIRE4(type1, type2, type3, type4, namespace-of-concept, concept); +Basic Concept Checking + Classes
++#include "boost/concept_check.hpp" + +template <class T> +struct Integer; // Is T a built-in integer type? + +template <class T> +struct SignedInteger; // Is T a built-in signed integer type? + +template <class T> +struct UnsignedInteger; // Is T a built-in unsigned integer type? + +template <class X, class Y> +struct Convertible; // Is X convertible to Y? + +template <class T> +struct Assignable; // Standard ref 23.1 + +template <class T> +struct SGIAssignable; + +template <class T> +struct DefaultConstructible; + +template <class T> +struct CopyConstructible; // Standard ref 20.1.3 + +template <class T> +struct EqualityComparable; // Standard ref 20.1.1 + +template <class T> +struct LessThanComparable; // Standard ref 20.1.2 + +template <class T> +struct Comparable; // The SGI STL LessThanComparable concept-Deprecated macros: +Iterator Concept + Checking Classes
++template <class Iter> +struct InputIterator; // Standard ref 24.1.1 Table 72 -- // Apply concept checks in class definitions. - BOOST_CLASS_REQUIRES(type, concept); - BOOST_CLASS_REQUIRES2(type1, type2, concept); - BOOST_CLASS_REQUIRES3(type1, type2, type3, concept); - BOOST_CLASS_REQUIRES4(type1, type2, type3, type4, concept); +template <class Iter, class T> +struct OutputIterator; // Standard ref 24.1.2 Table 73 + +template <class Iter> +struct ForwardIterator; // Standard ref 24.1.3 Table 74 + +template <class Iter> +struct Mutable_ForwardIterator; + +template <class Iter> +struct BidirectionalIterator; // Standard ref 24.1.4 Table 75 + +template <class Iter> +struct Mutable_BidirectionalIterator; + +template <class Iter> +struct RandomAccessIterator; // Standard ref 24.1.5 Table 76 + +template <class Iter> +struct Mutable_RandomAccessIterator;-Basic Concept Checking Classes
+Function Object Concept Checking + Classes
++#include "boost/concept_check.hpp" -- template <class T> - struct IntegerConcept; // Is T a built-in integer type? +template <class Func, class Return> +struct Generator; - template <class T> - struct SignedIntegerConcept; // Is T a built-in signed integer type? +template <class Func, class Return, class Arg> +struct UnaryFunction; - template <class T> - struct UnsignedIntegerConcept; // Is T a built-in unsigned integer type? +template <class Func, class Return, class First, class Second> +struct BinaryFunction; - template <class X, class Y> - struct ConvertibleConcept; // Is X convertible to Y? +template <class Func, class Arg> +struct UnaryPredicate; - template <class T> - struct AssignableConcept; // Standard ref 23.1 +template <class Func, class First, class Second> +struct BinaryPredicate; - template <class T> - struct SGIAssignableConcept; +template <class Func, class First, class Second> +struct Const_BinaryPredicate; - template <class T> - struct DefaultConstructibleConcept; +template <class Func, class Return> +struct AdaptableGenerator; - template <class T> - struct CopyConstructibleConcept; // Standard ref 20.1.3 +template <class Func, class Return, class Arg> +struct AdaptableUnaryFunction; - template <class T> - struct EqualityComparableConcept; // Standard ref 20.1.1 +template <class Func, class First, class Second> +struct AdaptableBinaryFunction; - template <class T> - struct LessThanComparableConcept; // Standard ref 20.1.2 +template <class Func, class Arg> +struct AdaptablePredicate; - template <class T> - struct ComparableConcept; // The SGI STL LessThanComparable concept +template <class Func, class First, class Second> +struct AdaptableBinaryPredicate;-Iterator Concept Checking Classes
+Container Concept + Checking Classes
++#include "boost/concept_check.hpp" -- template <class Iter> - struct InputIteratorConcept; // Standard ref 24.1.1 Table 72 +template <class C> +struct Container; // Standard ref 23.1 Table 65 - template <class Iter, class T> - struct OutputIteratorConcept; // Standard ref 24.1.2 Table 73 +template <class C> +struct Mutable_Container; - template <class Iter> - struct ForwardIteratorConcept; // Standard ref 24.1.3 Table 74 +template <class C> +struct ForwardContainer; - template <class Iter> - struct Mutable_ForwardIteratorConcept; +template <class C> +struct Mutable_ForwardContainer; - template <class Iter> - struct BidirectionalIteratorConcept; // Standard ref 24.1.4 Table 75 +template <class C> +struct ReversibleContainer; // Standard ref 23.1 Table 66 - template <class Iter> - struct Mutable_BidirectionalIteratorConcept; +template <class C> +struct Mutable_ReversibleContainer; - template <class Iter> - struct RandomAccessIteratorConcept; // Standard ref 24.1.5 Table 76 +template <class C> +struct RandomAccessContainer; - template <class Iter> - struct Mutable_RandomAccessIteratorConcept; +template <class C> +struct Mutable_RandomAccessContainer; + +template <class C> +struct Sequence; // Standard ref 23.1.1 + +template <class C> +struct FrontInsertionSequence; + +template <class C> +struct BackInsertionSequence; + +template <class C> +struct AssociativeContainer; // Standard ref 23.1.2 Table 69 + +template <class C> +struct UniqueAssociativeContainer; + +template <class C> +struct MultipleAssociativeContainer; + +template <class C> +struct SimpleAssociativeContainer; + +template <class C> +struct PairAssociativeContainer; + +template <class C> +struct SortedAssociativeContainer;-Function Object Concept Checking Classes
+Basic Archetype + Classes
++#include "boost/concept_archetype.hpp" -- template <class Func, class Return> - struct GeneratorConcept; +template <class T = int> +class null_archetype; // A type that models no concepts. - template <class Func, class Return, class Arg> - struct UnaryFunctionConcept; +template <class Base = null_archetype> +class default_constructible_archetype; - template <class Func, class Return, class First, class Second> - struct BinaryFunctionConcept; +template <class Base = null_archetype> +class assignable_archetype; - template <class Func, class Arg> - struct UnaryPredicateConcept; +template <class Base = null_archetype> +class copy_constructible_archetype; - template <class Func, class First, class Second> - struct BinaryPredicateConcept; +template <class Base = null_archetype> +class equality_comparable_archetype; - template <class Func, class First, class Second> - struct Const_BinaryPredicateConcept; - - template <class Func, class Return> - struct AdaptableGeneratorConcept; - - template <class Func, class Return, class Arg> - struct AdaptableUnaryFunctionConcept; - - template <class Func, class First, class Second> - struct AdaptableBinaryFunctionConcept; - - template <class Func, class Arg> - struct AdaptablePredicateConcept; - - template <class Func, class First, class Second> - struct AdaptableBinaryPredicateConcept; - +template <class T, class Base = null_archetype> +class convertible_to_archetype;-Container Concept Checking Classes
+Iterator Archetype + Classes
++#include "boost/concept_archetype.hpp" -- template <class C> - struct ContainerConcept; // Standard ref 23.1 Table 65 +template <class ValueType> +class trivial_iterator_archetype; - template <class C> - struct Mutable_ContainerConcept; +template <class ValueType> +class mutable_trivial_iterator_archetype; - template <class C> - struct ForwardContainerConcept; +template <class ValueType> +class input_iterator_archetype; - template <class C> - struct Mutable_ForwardContainerConcept; +template <class ValueType> +class forward_iterator_archetype; - template <class C> - struct ReversibleContainerConcept; // Standard ref 23.1 Table 66 +template <class ValueType> +class bidirectional_iterator_archetype; - template <class C> - struct Mutable_ReversibleContainerConcept; - - template <class C> - struct RandomAccessContainerConcept; - - template <class C> - struct Mutable_RandomAccessContainerConcept; - - template <class C> - struct SequenceConcept; // Standard ref 23.1.1 - - template <class C> - struct FrontInsertionSequenceConcept; - - template <class C> - struct BackInsertionSequenceConcept; - - template <class C> - struct AssociativeContainerConcept; // Standard ref 23.1.2 Table 69 - - template <class C> - struct UniqueAssociativeContainerConcept; - - template <class C> - struct MultipleAssociativeContainerConcept; - - template <class C> - struct SimpleAssociativeContainerConcept; - - template <class C> - struct PairAssociativeContainerConcept; - - template <class C> - struct SortedAssociativeContainerConcept; +template <class ValueType> +class random_access_iterator_archetype;+Function Object Archetype Classes
++#include "boost/concept_archetype.hpp" -Basic Archetype Classes
+template <class Arg, class Return> +class unary_function_archetype; -- template <class T = int> - class null_archetype; // A type that models no concepts. +template <class Arg1, class Arg2, class Return> +class binary_function_archetype; - template <class Base = null_archetype> - class default_constructible_archetype; +template <class Arg> +class predicate_archetype; - template <class Base = null_archetype> - class assignable_archetype; - - template <class Base = null_archetype> - class copy_constructible_archetype; - - template <class Base = null_archetype> - class equality_comparable_archetype; - - template <class T, class Base = null_archetype> - class convertible_to_archetype; +template <class Arg1, class Arg2> +class binary_predicate_archetype;-Iterator Archetype Classes
- -- template <class ValueType> - class trivial_iterator_archetype; - - template <class ValueType> - class mutable_trivial_iterator_archetype; - - template <class ValueType> - class input_iterator_archetype; - - template <class ValueType> - class forward_iterator_archetype; - - template <class ValueType> - class bidirectional_iterator_archetype; - - template <class ValueType> - class random_access_iterator_archetype; - -- -Function Object Archetype Classes
- -- template <class Arg, class Return> - class unary_function_archetype; - - template <class Arg1, class Arg2, class Return> - class binary_function_archetype; - - template <class Arg> - class predicate_archetype; - - template <class Arg1, class Arg2> - class binary_predicate_archetype; -- -Container Archetype Classes
- -+Container + Archetype Classes
+UNDER CONSTRUCTION--Back to Introduction -
-Prev: Implementation +Deprecated + Functions
++#include "boost/concept_check.hpp" -
-
-
Copyright © 2000 | -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) - |
+#include "boost/concept_check.hpp" + +// Apply concept checks in class definitions. +BOOST_CLASS_REQUIRE(type, namespace-of-concept, concept); +BOOST_CLASS_REQUIRE2(type1, type2, namespace-of-concept, concept); +BOOST_CLASS_REQUIRE3(type1, type2, type3, namespace-of-concept, concept); +BOOST_CLASS_REQUIRE4(type1, type2, type3, type4, namespace-of-concept, concept); + +// Apply concept checks in class definitions. +BOOST_CLASS_REQUIRES(type, concept); +BOOST_CLASS_REQUIRES2(type1, type2, concept); +BOOST_CLASS_REQUIRES3(type1, type2, type3, concept); +BOOST_CLASS_REQUIRES4(type1, type2, type3, type4, concept); ++ +
For each of the concepts documented here, the library includes an
+ identical concept checking class whose name ends in
+ “Concept
” For example, in
+ addition to RandomAccessIterator
, the library defines a
+ RandomAccessIteratorConcept
class template.
Back to Introduction
+ Prev: Implementation
Copyright © 2000 | + +Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), 2007 + David Abrahams. | +
-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; +For each concept there is a concept checking class template that 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 class + templates for all of the concepts used in the C++ standard library and a + few more. See the Reference section for a + complete list. 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 function templates 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 EqualityComparable;-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. +The template argument is the type to be checked. That is, the purpose of + EqualityComparable<X> is to make sure that + X 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. +
BOOST_CONCEPT_ASSERT()
-function_requires()
+The most versatile way of checking concept requirements is to use the +
+BOOST_CONCEPT_ASSERT()
macro. You can use this macro at any + scope, by passing a concept checking template specialization enclosed in + parentheses. Note: that means invocations of +BOOST_CONCEPT_ASSERT
will appear to use double + parentheses.+// In my library: +template <class T> +void generic_library_function(T x) +{ + BOOST_CONCEPT_ASSERT((EqualityComparable<T>)); + // ... +}; -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. +template <class It> +class generic_library_class +{ + BOOST_CONCEPT_ASSERT((RandomAccessIterator<It>)); + // ... +}; -- // In my library: - template <class T> - void generic_library_function(T x) - { - function_requires< EqualityComparableConcept<T> >(); - // ... - }; +// In the user's code: +class foo { + //... +}; - // In the user's code: - class foo { - //... - }; - - int main() { - foo f; - generic_library_function(f); - return 0; - } +int main() { + foo x; + generic_library_function(x); + generic_library_class<std::vector<char>::iterator> y; + //... +}+BOOST_CONCEPT_REQUIRES
-BOOST_CLASS_REQUIRE
+One of the nice things about the proposed C++0x syntax + for declaring concept constrained function templates is the way that + constraints are part of the function declaration, so clients will + see them.
-The BOOST_CLASS_REQUIRE macro can be used inside a class -definition to check whether some type models a concept. Make sure -that the arguments to this macro are simply identifiers. You may need -to use typedef to get your types into this form. - -BOOST_CONCEPT_ASSERT
can only express constraints + within the function template definition, which hides the constraint in the + function body. Aside from the loss of a self-documenting interface, + asserting conformance only in the function body can undesirably delay + checking if the function is explicitly instantiated in a different + translation unit from the one in which it is called, or if the compiler + does link-time instantiation.- // 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; - } +The BOOST_CONCEPT_REQUIRES macro can be used in a function + template declaration to check whether some type models a concept. It + accepts two arguments, a list of constraints, and the + function template's return type. The list of constraints takes the form of + a sequence of adjacent concept checking template specializations, + in double parentheses, and the function's return type must + also be parenthesized. For example, the standard
+stable_sort
+ algorithm might be declared as follows: class+template<typename RanIter> +BOOST_CONCEPT_REQUIRES( + ((Mutable_RandomAccessIterator<RanIter>)) + ((LessThanComparable<typename Mutable_RandomAccessIterator<RanIter>::value_type>)), + (void)) // return type + stable_sort(RanIter,RanIter);+Note that the algorithm requires that the value type of the iterator be + LessThanComparable, and it accesses that value type through the +
-Mutable_RandomAccessIterator
concept checking template. In + general, the Boost concept checking classes expose associated types as + nested member typedefs so that you can use this syntax, which mimics the + approach used in the concept support proposed for the next version of + C++.Example
+Multi-Type Concepts
--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 BOOST_CONCEPT_REQUIRES + is used with the ReadWritePropertyMap + concept, which takes two type parameters: a property map and the key type + for the map.
++template <class G, class Buffer, class BFSVisitor, + class ColorMap> +BOOST_CONCEPT_REQUIRES( + ((ReadWritePropertyMap<ColorMap, typename IncidenceGraph<G>::vertex_descriptor>)), + (void)) // return type +breadth_first_search(G& g, + typename graph_traits<IncidenceGraph>::vertex_descriptor s, + Buffer& Q, BFSVisitor vis, ColorMap color) +{ + typedef typename IncidenceGraph<G>::vertex_descriptor Vertex; + ... +}- - - - --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> >(); - ... - } +Although 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. The syntactic + requirements, at least, can easily be checked by creating a small program + and using BOOST_CONCEPT_ASSERT with the type and concept in + question. For example:
++// Make sure list<int> has bidirectional iterators. +BOOST_CONCEPT_ASSERT((BidirectionalIterator<std::list<int>::iterator>));+Prev: Concept Checking + Introduction
+
+ Next: Creating Concept Checking + Classes
-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. +
Copyright © 2000 | -
Copyright © 2000 | -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) - |