From 7dd50ca8f298ce8a86dd1c6a0ca3d5ea6670e6ba Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Nov 2007 03:54:19 +0000 Subject: [PATCH] Updated Concept Check library documentation. Changed BOOST_CONCEPT_WHERE to BOOST_CONCEPT_REQUIRES to be more consistent with the current C++0x proposal, which now uses a "requires" keyword in lieu of "where." Factored GCC workarounds into the BOOST_CONCEPT_USAGE macro. [SVN r40769] --- bad_error_eg.cpp | 19 +- concept_check.htm | 536 ++++++++++++++--------------- concept_covering.htm | 225 +++++++------ creating_concepts.htm | 237 +++++++------ fake_sort.hpp | 2 +- implementation.htm | 225 ++++++------- include/boost/concept/usage.hpp | 17 +- include/boost/concept/where.hpp | 49 +-- include/boost/concept_check.hpp | 223 ++----------- prog_with_concepts.htm | 164 +++++---- reference.htm | 573 ++++++++++++++++++-------------- using_concept_check.htm | 359 +++++++++----------- 12 files changed, 1293 insertions(+), 1336 deletions(-) diff --git a/bad_error_eg.cpp b/bad_error_eg.cpp index 644ac4c..5f8d892 100644 --- a/bad_error_eg.cpp +++ b/bad_error_eg.cpp @@ -1,13 +1,14 @@ +#include +#include +#include "algorithm" + +int main() +{ + std::vector > v; + std_::stable_sort(v.begin(), v.end()); +} + // (C) Copyright Jeremy Siek 2000. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -int main() { - std::list v; - std::stable_sort(v.begin(), v.end()); - return 0; -} diff --git a/concept_check.htm b/concept_check.htm index 194b0c2..0f70167 100644 --- a/concept_check.htm +++ b/concept_check.htm @@ -1,312 +1,330 @@ - - - -Concept Check Library + + + + + + + + + + + + + Concept Check Library + - -C++ Boost + + C++ Boost
-
+

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

-

-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 + RandomAccessIterator is no different to the compiler than one + named T. Furthermore,

-
    -
  • Compiler error messages resulting from incorrect template - arguments can be particularly difficult to decipher. Often times - the error does not point to the location of the template - call-site, but instead exposes the internals of the template, which - the user should never have to see.
  • +
      +
    • Compiler error messages resulting from incorrect template arguments + can be particularly difficult to decipher. Often times the error does not + point to the location of the template call-site, but instead exposes the + internals of the template, which the user should never have to see.
    • -
    • The documented concept requirements may not fully cover - the template, meaning the user could get a compiler error even - though the supplied template arguments meet the documented - requirements.
    • +
    • Without checking from the compiler, the documented requirements are + oftentimes vague, incorrect, or nonexistent, so a user cannot know + exactly what kind of arguments are expected.
    • -
    • The documented concept requirements may be too stringent, - requiring more than is really needed by the template.
    • +
    • The documented concept requirements may not fully cover the + needs of the actual template, meaning the user could get a compiler error + even though the supplied template arguments meet the documented + requirements.
    • -
    • The requirements are not explicitly stated in the code, which - makes the code harder to understand. Also, the code may - get out-of-sync with the documented requirements.
    • -
    +
  • The documented concept requirements may be too stringent, requiring + more than is really needed by the template.
  • -The Boost Concept Checking Library provides: +
  • Concept names in code may drift out-of-sync with the documented + requirements.
  • +

The Boost Concept Checking Library provides: -

    -
  • A mechanism for inserting compile-time checks of template - parameters.
  • +
      +
    • A mechanism for inserting compile-time checks on template parameters + at their point of use.
    • -
    • A framework for specifying concept requirements though concept - checking classes.
    • +
    • A framework for specifying concept requirements though concept + checking classes.
    • -
    • A mechanism for verifying that concept requirements cover the template.
    • +
    • A mechanism for verifying that concept requirements cover the + template.
    • -
    • A suite of concept checking classes and archetype classes that - match the concept requirements in the C++ Standard Library.
    • -
    +
  • A suite of concept checking classes and archetype classes that match + the concept requirements in the C++ Standard Library.
  • -The mechanisms use standard C++ and introduce no run-time -overhead. The main cost of using the mechanism is in compile-time. +
  • An alternative to the use of traits classes for accessing associated + types that mirrors the syntax proposed for the next C++ standard.
  • +

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.

-
    -
  1. Introduction
  2. -
  3. Motivating Example
  4. -
  5. History
  6. -
  7. Publications
  8. -
  9. Acknowledgements
  10. -
  11. Using Concept Checks
  12. -
  13. Creating Concept Checking Classes
  14. -
  15. Concept Covering and Archetypes
  16. -
  17. Programming With Concepts
  18. -
  19. Implementation
  20. -
  21. Reference
  22. -
+
    +
  1. Introduction
  2. -

    -Jeremy Siek contributed -this library. Beman Dawes -managed the formal review. +

  3. Motivating Example
  4. -

    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. +
  5. History
  6. -

    -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. +

  7. Publications
  8. -

    -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. +

  9. Acknowledgements
  10. -

    -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.. +

  11. Using Concept Checks
  12. -

    Motivating Example

    +
  13. Creating Concept Checking + Classes
  14. -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. +
  15. Concept Covering and + Archetypes
  16. -
    +    
  17. Programming With Concepts
  18. + +
  19. Implementation
  20. + +
  21. Reference
  22. +
+ +

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.

+ +

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. + +

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..

+ +

Motivating + Example

+ +

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.

+
   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: -
+  

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 *> &'
+  

Attempting to compile this code with Gnu C++ produces the following + compiler error:

+
+/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. +

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:

-
    -
  1. The location of the error, line 6 of bad_error_eg.cpp - is not pointed to by the error message, despite the fact that Gnu C++ - prints up to 4 levels deep in the instantiation stack. -
  2. There is no textual correlation between the error message and the - documented requirements for std::stable_sort() and for - -RandomAccessIterator. -
  3. The error message is overly long, listing functions internal - to the STL that the user does not (and should not!) know or care - about. -
  4. With so many internal library functions listed in the error - message, the programmer could easily infer that the error is due - to the library, rather than to his or her own code. -
+
    +
  1. There is no textual correlation between the error message and the + documented requirements for std::stable_sort() and for LessThanComparable.
  2. -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): +
  3. The error message is overly long, listing functions internal + to the STL (e.g. __insertion_sort) that the user + does not (and should not!) know or care about.
  4. -
    -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 *> &'
    +    
  5. With so many internal library functions listed in the error message, + the programmer could easily infer that the problem is in the library, + rather than in his or her own code.
  6. +
+ +

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

+
+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. +

This message rectifies several of the shortcomings of the standard error + messages.

-
    -
  • The location of the error, bad_error_eg.cpp:6 is - specified in the error message. -
  • The message refers explicitly to concepts that the user can look - up in the STL documentation ( -RandomAccessIterator). -
  • The error message is now much shorter and does not reveal - internal STL functions. -
  • The presence of concept_check.hpp in the error message - alerts the user to the fact that the error lies in the user code and - not in the library implementation. -
+
    +
  • The message refers explicitly to concepts that the user can look up + in the STL documentation (LessThanComparable).
  • -

    History

    +
  • The error message is now much shorter and does not reveal + internal STL functions, nor indeed does it even point + to std::stable_sort.
  • -An earlier version of this concept checking system was developed by -the author while working at SGI in their C++ compiler and library -group. The earlier version is now part of the SGI STL distribution. The -boost concept checking library differs from the concept checking in -the SGI STL in that the definition of concept checking classes has -been greatly simplified, at the price of less helpful verbiage in the -error messages. +
  • The presence of concept_check.hpp in the error message + alerts the user to the fact that the error lies in the user code and not + in the library implementation.
  • +
-

Publications

+

History

- +

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. +

-

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

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. -

-Next: Using Concept Checks +

Next: Using Concept + Checks

+
-
-
- - -
Copyright © 2000 -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) -
+ + + - - + + +
Copyright © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. +
+ + 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 @@ - - - -Concept Covering and Archetypes - -C++ Boost + -
+ + + + + -

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. + Concept Covering and Archetypes + + + -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. + + C++ Boost
-
-  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

+ +

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.

+
+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. +

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. - -

-  {
-    typedef less_than_comparable_archetype< 
-        sgi_assignable_archetype<> > ValueType;
-    random_access_iterator_archetype<ValueType> ri;
-    std::stable_sort(ri, ri);
-  }
+  

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.

+
+{
+  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 +

Next: Programming with + Concepts
+ Prev: Creating Concept Checking + Classes
+


-
-
- - -
Copyright © 2000 -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) -
+ + + - - + +
Copyright © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. +
+ + 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 @@ - - - -Creating Concept Checking Classes - -C++ Boost + -
+ + + + + + + + -

Creating Concept Checking Classes

+ 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. + + C++ Boost
-

-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. +

Creating + Concept Checking Classes

-

-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:

+
+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

+ +

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 + 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

+ +

You may be wondering why we declared 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). +

Unfortunately, that code wouldn't have worked out so well, because it + unintentionally imposes the requirement that 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.

-

-Next: Concept Covering and Archetypes
-Prev: Using Concept Checks +

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.

+

Similarity to Proposed C++0x Language Support for Concepts

-
-
- - -
Copyright © 2000 -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) -
+

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
+ Prev: Using Concept + Checks

+
+ + + + + + +
Copyright © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. +
+ + 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 - BOOST_CONCEPT_WHERE( + BOOST_CONCEPT_REQUIRES( ((Mutable_RandomAccessIterator)) ((LessThanComparable::value_type>)) diff --git a/implementation.htm b/implementation.htm index b2c3db9..6df94ca 100644 --- a/implementation.htm +++ b/implementation.htm @@ -1,50 +1,59 @@ - - - -Concept Checking Implementation - -C++ Boost + -
+ + + + + + + + + -

Implementation

+ Concept Checking Implementation + -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: + + C++ Boost
-
+  

Warning

+ +

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 BOOST_CLASS_REQUIRES + and constraints() functions, which are still supported + but deprecated.

+ +

Implementation

+ +

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:

+
   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. - -
+  

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. - -
+  

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. - -
+  

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. - -
+  

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 © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. +
+ + diff --git a/include/boost/concept/usage.hpp b/include/boost/concept/usage.hpp index 399bd4c..9af8ca3 100755 --- a/include/boost/concept/usage.hpp +++ b/include/boost/concept/usage.hpp @@ -21,9 +21,20 @@ struct usage_requirements ~usage_requirements() { ((Model*)0)->~Model(); } }; -# define BOOST_CONCEPT_USAGE(model) \ - BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements)); \ - ~model() +# if BOOST_WORKAROUND(__GNUC__, <= 3) + +# define BOOST_CONCEPT_USAGE(model) \ + model(); /* at least 2.96 and 3.4.3 both need this :( */ \ + BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements)); \ + ~model() + +# else + +# define BOOST_CONCEPT_USAGE(model) \ + BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements)); \ + ~model() + +# endif # endif diff --git a/include/boost/concept/where.hpp b/include/boost/concept/where.hpp index c91c1f9..5570b64 100755 --- a/include/boost/concept/where.hpp +++ b/include/boost/concept/where.hpp @@ -1,8 +1,8 @@ // Copyright David Abrahams 2006. Distributed under the Boost // Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_CONCEPT_WHERE_DWA2006430_HPP -# define BOOST_CONCEPT_WHERE_DWA2006430_HPP +#ifndef BOOST_CONCEPT_REQUIRES_DWA2006430_HPP +# define BOOST_CONCEPT_REQUIRES_DWA2006430_HPP # include # include @@ -12,7 +12,7 @@ namespace boost { // Template for use in handwritten assertions template -struct where_ : More +struct requires_ : More { # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) typedef typename More::type type; @@ -23,41 +23,52 @@ struct where_ : More // Template for use by macros, where models must be wrapped in parens. // This isn't in namespace detail to keep extra cruft out of resulting // error messages. -template -struct _where_ : More +template +struct _requires_ { -# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - typedef typename More::type type; -# endif + enum { value = 0 }; BOOST_CONCEPT_ASSERT_FN(ModelFn); }; -#define BOOST_CONCEPT_WHERE_OPEN(r,data,t) ::boost::_where_ +template +struct Requires_ : ::boost::parameter::aux::unaryfunptr_arg_type +{ +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + typedef typename ::boost::parameter::aux::unaryfunptr_arg_type::type type; +# endif +}; + + +#define BOOST_CONCEPT_REQUIRES_(r,data,t) + (::boost::_requires_::value) #if defined(NDEBUG) || BOOST_WORKAROUND(BOOST_MSVC, < 1300) -# define BOOST_CONCEPT_WHERE(models, result) \ +# define BOOST_CONCEPT_REQUIRES(models, result) \ typename ::boost::parameter::aux::unaryfunptr_arg_type::type #elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Same thing as below without the initial typename -# define BOOST_CONCEPT_WHERE(models, result) \ - BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_OPEN, ~, models) \ +# define BOOST_CONCEPT_REQUIRES(models, result) \ + ::boost::Requires_< \ + (0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \ ::boost::parameter::aux::unaryfunptr_arg_type \ - BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_CLOSE, ~, models)::type + >::type #else // This just ICEs on MSVC6 :( -# define BOOST_CONCEPT_WHERE(models, result) \ - typename BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_OPEN, ~, models) \ - ::boost::parameter::aux::unaryfunptr_arg_type \ - BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_CLOSE, ~, models)::type +# define BOOST_CONCEPT_REQUIRES(models, result) \ + typename ::boost::Requires_< \ + (0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \ + void(*)result \ + >::type #endif +// C++0x proposed syntax changed. This supports an older usage +#define BOOST_CONCEPT_WHERE(models,result) BOOST_CONCEPT_REQUIRES(models,result) + } // namespace boost::concept_check -#endif // BOOST_CONCEPT_WHERE_DWA2006430_HPP +#endif // BOOST_CONCEPT_REQUIRES_DWA2006430_HPP diff --git a/include/boost/concept_check.hpp b/include/boost/concept_check.hpp index 555f2b4..4e9fddf 100644 --- a/include/boost/concept_check.hpp +++ b/include/boost/concept_check.hpp @@ -62,9 +62,6 @@ namespace boost // BOOST_concept(Integer, (T)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Integer(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(Integer) { x.error_type_must_be_an_integer_type(); @@ -90,9 +87,6 @@ namespace boost # endif BOOST_concept(SignedInteger,(T)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - SignedInteger(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(SignedInteger) { x.error_type_must_be_a_signed_integer_type(); } @@ -110,9 +104,6 @@ namespace boost # endif BOOST_concept(UnsignedInteger,(T)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - UnsignedInteger(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(UnsignedInteger) { x.error_type_must_be_an_unsigned_integer_type(); } @@ -135,9 +126,6 @@ namespace boost BOOST_concept(DefaultConstructible,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - DefaultConstructible(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(DefaultConstructible) { TT a; // require default constructor ignore_unused_variable_warning(a); @@ -146,13 +134,9 @@ namespace boost BOOST_concept(Assignable,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Assignable(); // at least 2.96 and 3.4.3 both need this :( -#endif - BOOST_CONCEPT_USAGE(Assignable) { #if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL - a = a; // require assignment operator + a = a; // require assignment operator #endif const_constraints(a); } @@ -166,12 +150,9 @@ namespace boost TT a; }; + BOOST_concept(CopyConstructible,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - CopyConstructible(); // at least 2.96 and 3.4.3 both need this :( -#endif - BOOST_CONCEPT_USAGE(CopyConstructible) { TT a(b); // require copy constructor TT* ptr = &a; // require address of operator @@ -191,10 +172,6 @@ namespace boost // The SGI STL version of Assignable requires copy constructor and operator= BOOST_concept(SGIAssignable,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - SGIAssignable(); // at least 2.96 and 3.4.3 both need this :( -#endif - BOOST_CONCEPT_USAGE(SGIAssignable) { TT b(a); #if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL @@ -216,9 +193,6 @@ namespace boost BOOST_concept(Convertible,(X)(Y)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Convertible(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(Convertible) { Y y = x; ignore_unused_variable_warning(y); @@ -244,9 +218,6 @@ namespace boost BOOST_concept(EqualityComparable,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - EqualityComparable(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(EqualityComparable) { require_boolean_expr(a == b); require_boolean_expr(a != b); @@ -257,9 +228,6 @@ namespace boost BOOST_concept(LessThanComparable,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - LessThanComparable(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(LessThanComparable) { require_boolean_expr(a < b); } @@ -270,9 +238,6 @@ namespace boost // This is equivalent to SGI STL's LessThanComparable. BOOST_concept(Comparable,(TT)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Comparable(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(Comparable) { require_boolean_expr(a < b); require_boolean_expr(a > b); @@ -283,18 +248,6 @@ namespace boost TT a, b; }; -#if BOOST_WORKAROUND(__GNUC__, <= 3) -#define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \ - BOOST_concept(NAME, (First)(Second)) \ - { \ - NAME(); \ - BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \ - private: \ - bool constraints_() { return a OP b; } \ - First a; \ - Second b; \ - } -#else #define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \ BOOST_concept(NAME, (First)(Second)) \ { \ @@ -304,20 +257,7 @@ namespace boost First a; \ Second b; \ } -#endif -#if BOOST_WORKAROUND(__GNUC__, <= 3) -#define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \ - BOOST_concept(NAME, (Ret)(First)(Second)) \ - { \ - NAME(); \ - BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \ - private: \ - Ret constraints_() { return a OP b; } \ - First a; \ - Second b; \ - } -#else #define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \ BOOST_concept(NAME, (Ret)(First)(Second)) \ { \ @@ -327,7 +267,6 @@ namespace boost First a; \ Second b; \ } -#endif BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(==, EqualOp); BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(!=, NotEqualOp); @@ -347,9 +286,6 @@ namespace boost BOOST_concept(Generator,(Func)(Return)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Generator(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(Generator) { test(is_void()); } private: @@ -370,9 +306,6 @@ namespace boost BOOST_concept(UnaryFunction,(Func)(Return)(Arg)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - UnaryFunction(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void()); } private: @@ -394,9 +327,6 @@ namespace boost BOOST_concept(BinaryFunction,(Func)(Return)(First)(Second)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - BinaryFunction(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(BinaryFunction) { test(is_void()); } private: void test(boost::mpl::false_) @@ -418,9 +348,6 @@ namespace boost BOOST_concept(UnaryPredicate,(Func)(Arg)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - UnaryPredicate(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(UnaryPredicate) { require_boolean_expr(f(arg)); // require operator() returning bool } @@ -431,9 +358,6 @@ namespace boost BOOST_concept(BinaryPredicate,(Func)(First)(Second)) { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - BinaryPredicate(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(BinaryPredicate) { require_boolean_expr(f(a, b)); // require operator() returning bool } @@ -447,9 +371,6 @@ namespace boost BOOST_concept(Const_BinaryPredicate,(Func)(First)(Second)) : BinaryPredicate { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Const_BinaryPredicate(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(Const_BinaryPredicate) { const_constraints(f); } @@ -468,9 +389,6 @@ namespace boost { typedef typename Func::result_type result_type; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AdaptableGenerator(); // at least 2.96 and 3.4.3 both need this :( -#endif BOOST_CONCEPT_USAGE(AdaptableGenerator) { BOOST_CONCEPT_ASSERT((Convertible)); @@ -483,9 +401,6 @@ namespace boost typedef typename Func::argument_type argument_type; typedef typename Func::result_type result_type; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AdaptableUnaryFunction(); // at least 2.96 and 3.4.3 both need this :( -#endif ~AdaptableUnaryFunction() { BOOST_CONCEPT_ASSERT((Convertible)); @@ -505,9 +420,6 @@ namespace boost typedef typename Func::second_argument_type second_argument_type; typedef typename Func::result_type result_type; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AdaptableBinaryFunction(); // at least 2.96 and 3.4.3 both need this :( -#endif ~AdaptableBinaryFunction() { BOOST_CONCEPT_ASSERT((Convertible)); @@ -520,18 +432,12 @@ namespace boost : UnaryPredicate , AdaptableUnaryFunction { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AdaptablePredicate(); // at least 2.96 and 3.4.3 both need this :( -#endif }; BOOST_concept(AdaptableBinaryPredicate,(Func)(First)(Second)) : BinaryPredicate , AdaptableBinaryFunction { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AdaptableBinaryPredicate(); // at least 2.96 and 3.4.3 both need this :( -#endif }; //=========================================================================== @@ -547,10 +453,7 @@ namespace boost typedef typename boost::detail::iterator_traits::pointer pointer; typedef typename boost::detail::iterator_traits::iterator_category iterator_category; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - InputIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~InputIterator() + BOOST_CONCEPT_USAGE(InputIterator) { BOOST_CONCEPT_ASSERT((SignedInteger)); BOOST_CONCEPT_ASSERT((Convertible)); @@ -567,10 +470,7 @@ namespace boost BOOST_concept(OutputIterator,(TT)(ValueT)) : Assignable { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - OutputIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~OutputIterator() { + BOOST_CONCEPT_USAGE(OutputIterator) { ++i; // require preincrement operator i++; // require postincrement operator @@ -584,10 +484,7 @@ namespace boost BOOST_concept(ForwardIterator,(TT)) : InputIterator { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - ForwardIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~ForwardIterator() + BOOST_CONCEPT_USAGE(ForwardIterator) { BOOST_CONCEPT_ASSERT((Convertible< BOOST_DEDUCED_TYPENAME ForwardIterator::iterator_category @@ -605,10 +502,7 @@ namespace boost BOOST_concept(Mutable_ForwardIterator,(TT)) : ForwardIterator { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_ForwardIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_ForwardIterator() { + BOOST_CONCEPT_USAGE(Mutable_ForwardIterator) { *i++ = *i; // require postincrement and assignment } private: @@ -618,10 +512,7 @@ namespace boost BOOST_concept(BidirectionalIterator,(TT)) : ForwardIterator { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - BidirectionalIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~BidirectionalIterator() + BOOST_CONCEPT_USAGE(BidirectionalIterator) { BOOST_CONCEPT_ASSERT((Convertible< BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category @@ -639,10 +530,7 @@ namespace boost : BidirectionalIterator , Mutable_ForwardIterator { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_BidirectionalIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_BidirectionalIterator() + BOOST_CONCEPT_USAGE(Mutable_BidirectionalIterator) { *i-- = *i; // require postdecrement and assignment } @@ -654,10 +542,7 @@ namespace boost : BidirectionalIterator , Comparable { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - RandomAccessIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~RandomAccessIterator() + BOOST_CONCEPT_USAGE(RandomAccessIterator) { BOOST_CONCEPT_ASSERT((Convertible< BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category @@ -682,10 +567,7 @@ namespace boost : RandomAccessIterator , Mutable_BidirectionalIterator { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_RandomAccessIterator(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_RandomAccessIterator() + BOOST_CONCEPT_USAGE(Mutable_RandomAccessIterator) { i[n] = *i; // require element access and assignment } @@ -707,10 +589,7 @@ namespace boost typedef typename C::const_pointer const_pointer; typedef typename C::const_iterator const_iterator; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Container(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Container() + BOOST_CONCEPT_USAGE(Container) { BOOST_CONCEPT_ASSERT((InputIterator)); const_constraints(c); @@ -737,10 +616,7 @@ namespace boost typedef typename C::iterator iterator; typedef typename C::pointer pointer; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_Container(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_Container() + BOOST_CONCEPT_USAGE(Mutable_Container) { BOOST_CONCEPT_ASSERT(( Assignable)); @@ -760,10 +636,7 @@ namespace boost BOOST_concept(ForwardContainer,(C)) : Container { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - ForwardContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~ForwardContainer() + BOOST_CONCEPT_USAGE(ForwardContainer) { BOOST_CONCEPT_ASSERT(( ForwardIterator< @@ -776,10 +649,7 @@ namespace boost : ForwardContainer , Mutable_Container { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_ForwardContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_ForwardContainer() + BOOST_CONCEPT_USAGE(Mutable_ForwardContainer) { BOOST_CONCEPT_ASSERT(( Mutable_ForwardIterator< @@ -795,10 +665,7 @@ namespace boost C::const_reverse_iterator const_reverse_iterator; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - ReversibleContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~ReversibleContainer() + BOOST_CONCEPT_USAGE(ReversibleContainer) { BOOST_CONCEPT_ASSERT(( BidirectionalIterator< @@ -823,10 +690,7 @@ namespace boost { typedef typename C::reverse_iterator reverse_iterator; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_ReversibleContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_ReversibleContainer() + BOOST_CONCEPT_USAGE(Mutable_ReversibleContainer) { typedef typename Mutable_ForwardContainer::iterator iterator; BOOST_CONCEPT_ASSERT((Mutable_BidirectionalIterator)); @@ -845,10 +709,7 @@ namespace boost typedef typename C::size_type size_type; typedef typename C::const_reference const_reference; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - RandomAccessContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~RandomAccessContainer() + BOOST_CONCEPT_USAGE(RandomAccessContainer) { BOOST_CONCEPT_ASSERT(( RandomAccessIterator< @@ -875,10 +736,7 @@ namespace boost private: typedef Mutable_RandomAccessContainer self; public: -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Mutable_RandomAccessContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Mutable_RandomAccessContainer() + BOOST_CONCEPT_USAGE(Mutable_RandomAccessContainer) { BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator)); BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator)); @@ -900,10 +758,7 @@ namespace boost // ... so why aren't we following the standard? --DWA , DefaultConstructible { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - Sequence(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~Sequence() + BOOST_CONCEPT_USAGE(Sequence) { S c(n), @@ -940,10 +795,7 @@ namespace boost BOOST_concept(FrontInsertionSequence,(S)) : Sequence { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - FrontInsertionSequence(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~FrontInsertionSequence() + BOOST_CONCEPT_USAGE(FrontInsertionSequence) { c.push_front(t); c.pop_front(); @@ -956,10 +808,7 @@ namespace boost BOOST_concept(BackInsertionSequence,(S)) : Sequence { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - BackInsertionSequence(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~BackInsertionSequence() + BOOST_CONCEPT_USAGE(BackInsertionSequence) { c.push_back(t); c.pop_back(); @@ -986,10 +835,7 @@ namespace boost typedef typename C::value_compare value_compare; typedef typename C::iterator iterator; -#if BOOST_WORKAROUND(__GNUC__, <= 3) - AssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~AssociativeContainer() + BOOST_CONCEPT_USAGE(AssociativeContainer) { i = c.find(k); r = c.equal_range(k); @@ -1025,10 +871,7 @@ namespace boost BOOST_concept(UniqueAssociativeContainer,(C)) : AssociativeContainer { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - UniqueAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~UniqueAssociativeContainer() + BOOST_CONCEPT_USAGE(UniqueAssociativeContainer) { C c(first, last); @@ -1046,10 +889,7 @@ namespace boost BOOST_concept(MultipleAssociativeContainer,(C)) : AssociativeContainer { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - MultipleAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~MultipleAssociativeContainer() + BOOST_CONCEPT_USAGE(MultipleAssociativeContainer) { C c(first, last); @@ -1068,10 +908,7 @@ namespace boost BOOST_concept(SimpleAssociativeContainer,(C)) : AssociativeContainer { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - SimpleAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~SimpleAssociativeContainer() + BOOST_CONCEPT_USAGE(SimpleAssociativeContainer) { typedef typename C::key_type key_type; typedef typename C::value_type value_type; @@ -1082,10 +919,7 @@ namespace boost BOOST_concept(PairAssociativeContainer,(C)) : AssociativeContainer { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - PairAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~PairAssociativeContainer() + BOOST_CONCEPT_USAGE(PairAssociativeContainer) { typedef typename C::key_type key_type; typedef typename C::value_type value_type; @@ -1099,10 +933,7 @@ namespace boost : AssociativeContainer , ReversibleContainer { -#if BOOST_WORKAROUND(__GNUC__, <= 3) - SortedAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :( -#endif - ~SortedAssociativeContainer() + BOOST_CONCEPT_USAGE(SortedAssociativeContainer) { C c(kc), diff --git a/prog_with_concepts.htm b/prog_with_concepts.htm index dd58d15..2aa9e22 100644 --- a/prog_with_concepts.htm +++ b/prog_with_concepts.htm @@ -1,57 +1,55 @@ - - - -Programming With Concepts - -C++ Boost + -
+ + + + + -

Programming with Concepts

+ + -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. + Programming With Concepts + + + -

-Requirement Minimization Principle: Minimize the requirements -on the input parameters of a component to increase its reusability. + + C++ Boost
-

-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. +

Programming with Concepts

-

-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 © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), + 2007 David Abrahams. +
+ + diff --git a/reference.htm b/reference.htm index d99909f..f5dd9d9 100644 --- a/reference.htm +++ b/reference.htm @@ -1,308 +1,391 @@ - - - -Boost Concept Checking Reference - - -C++ Boost + -
+ + + + + -

Reference

+ + + + -
    -
  1. Functions
  2. -
  3. Macros
  4. -
  5. Basic Concept Checking Classes
  6. -
  7. Iterator Concept Checking Classes
  8. -
  9. Function Object Concept Checking Classes
  10. -
  11. Container Concept Checking Classes
  12. -
  13. Basic Archetype Classes
  14. -
  15. Iterator Archetype Classes
  16. -
  17. Function Object Archetype Classes
  18. -
  19. Container Archetype Classes
  20. -
+ Boost Concept Checking Reference + -

Functions

+ + C++ Boost
-
-  template <class Concept>
-  void function_requires();
+  

Reference

+ +
    +
  1. Macros
  2. + +
  3. Basic Concept Checking Classes
  4. + +
  5. Iterator Concept Checking + Classes
  6. + +
  7. Function Object Concept Checking + Classes
  8. + +
  9. Container Concept Checking + Classes
  10. + +
  11. Basic Archetype Classes
  12. + +
  13. Iterator Archetype Classes
  14. + +
  15. Function Object Archetype + Classes
  16. + +
  17. Container Archetype Classes
  18. + +
  19. Deprecated Functions
  20. + +
  21. Deprecated Macros
  22. + +
  23. Deprecated Concept + Checking Classes
  24. +
+ +

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) -
+template <class Concept> +void function_requires(); +
- - +

Deprecated + Macros

+
+#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);
+
+ +

Deprecated Concept Checking + Classes

+ +

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 © 2000Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), 2007 + David Abrahams.
+ + diff --git a/using_concept_check.htm b/using_concept_check.htm index ff120f8..3dc311d 100644 --- a/using_concept_check.htm +++ b/using_concept_check.htm @@ -1,227 +1,186 @@ - - - -Using Concept Checks - -C++ Boost + -
+ + + + + + + + -

Using Concept Checks

+ 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. + + C++ Boost
-

-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. +

Using Concept + Checks

-
-  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. 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.

-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. - -
-  // 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. + + + -
-  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
- -
Copyright © 2000 -Jeremy Siek(jsiek@osl.iu.edu) -Andrew Lumsdaine(lums@osl.iu.edu) -
- - - + Jeremy Siek(jsiek@osl.iu.edu) Andrew + Lumsdaine(lums@osl.iu.edu), 2007 + David Abrahams. + + + +