From 75f85ba7aa8f955720a380362ba9a4e89d213362 Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Sat, 9 Dec 2000 23:00:15 +0000 Subject: [PATCH] more reorganization and editing of the concept docs [SVN r8437] --- concept_check.htm | 115 ++++++++++++++++++++---- concept_covering.htm | 35 ++++++++ creating_concepts.htm | 40 +++++++++ implementation.htm | 88 +++++++++++++++++-- prog_with_concepts.htm | 42 +++++++++ reference.htm | 111 +++++++++++++++-------- using_concept_check.htm | 190 +++++++++++++++++++++++++--------------- 7 files changed, 486 insertions(+), 135 deletions(-) diff --git a/concept_check.htm b/concept_check.htm index 5ef280b..7abcf2b 100644 --- a/concept_check.htm +++ b/concept_check.htm @@ -24,35 +24,87 @@

header -boost/concept_check.hpp and +boost/concept_check.hpp +
and boost/concept_archetype.hpp

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 -explicitly handling concepts. As a result, it can be difficult to -insure that a concrete type meets the requirements of the concept it -is supposed to represent. Error messages resulting from incorrect use -of a concrete type can be particularly difficult to decipher. The -Boost Concept Checking Library provides mechanisms for checking -parameters in C++ template libraries. The mechanisms use standard C++ -and introduce no run-time overhead. The main cost of using the -mechanism is in compile-time. +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. Furthemore, the following +problems occur: +

+ +The Boost Concept Checking Library provides: + + + +The mechanisms use standard C++ and introduce no run-time +overhead. The main cost of using the mechanism is in compile-time. + +

+Any programmer writing class or function templates ought to make +concept checking a normal part of their code-writing routine. A +concept check should be inserted for each template paramter 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.

  1. Introduction
  2. Motivating Example
  3. -
  4. Using Concept Checks
  5. +
  6. Using Concept Checks
  7. Creating Concept Checking Classes
  8. Concept Covering and Archetypes
  9. Programming With Concepts
  10. Implementation
  11. Reference
  12. -
  13. History
  14. +
  15. History
  16. Publications
  17. Acknowledgements
@@ -186,14 +238,14 @@ informative message (and is in fact what the Boost Concept Checking Library produces):
-concept_check.hpp: In method `void LessThanComparable_concept
+boost/concept_check.hpp: In method `void LessThanComparableConcept
   <_List_iterator<foo,foo &,foo *> >::constraints()':
-concept_check.hpp:334:   instantiated from `RandomAccessIterator_concept
+boost/concept_check.hpp:334:   instantiated from `RandomAccessIteratorConcept
   <_List_iterator<foo,foo &,foo *> >::constraints()'
 bad_error_eg.cpp:9:   instantiated from `stable_sort<_List_iterator
   <foo,foo &,foo *> >(_List_iterator<foo,foo &,foo *>, 
   _List_iterator<foo,foo &,foo *>)'
-concept_check.hpp:209: no match for `_List_iterator<foo,foo &,foo *> &
+boost/concept_check.hpp:209: no match for `_List_iterator<foo,foo &,foo *> &
   < _List_iterator<foo,foo &,foo *> &'
 
@@ -215,14 +267,45 @@ RandomAccessIterator). implementation. +

History

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

Publications

+ + + +

Acknowledgements

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

+Next: Using Concept Checks


Copyright © 2000 -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu)
diff --git a/concept_covering.htm b/concept_covering.htm index 3c4afa3..ae2a567 100644 --- a/concept_covering.htm +++ b/concept_covering.htm @@ -1,3 +1,23 @@ + + + +Concept Covering and Archetypes + +C++ Boost + +

Concept Covering and Archetypes

@@ -94,3 +114,18 @@ layered archetype can be used. } +Next: Programming with Concepts
+Prev: Creating Concept Checking Classes + +
+
+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/creating_concepts.htm b/creating_concepts.htm index db5941e..10ade8a 100644 --- a/creating_concepts.htm +++ b/creating_concepts.htm @@ -1,3 +1,25 @@ + + + +Creating Concept Checking Classes + +C++ Boost + +
+ +

Creating Concept Checking Classes

As an example of how to create a concept checking class, we look @@ -70,3 +92,21 @@ Since objects of the constraints class template are never instantiated, the default constructor for the concept checking class is never instantiated. Hence the data member's default constructors are never instantiated (C++ Standard Section 14.7.1 9). + +

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


+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/implementation.htm b/implementation.htm index 585e034..ee1ec22 100644 --- a/implementation.htm +++ b/implementation.htm @@ -1,3 +1,23 @@ + + + +Concept Checking Implementation + +C++ Boost + +

Implementation

@@ -26,14 +46,16 @@ can be applied to the std::stable_sort() function:
   template <class RandomAccessIterator>
-  void stable_sort_constraints(RandomAccessIterator i) {
+  void stable_sort_constraints(RandomAccessIterator i)
+  {
     typename std::iterator_traits<RandomAccessIterator>
       ::difference_type n;
     i += n;  // exercise the requirements for RandomAccessIterator
     ...
   }
   template <class RandomAccessIterator>
-  void stable_sort(RandomAccessIterator first, RandomAccessIterator last) {
+  void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
+  {
     typedef void (*fptr_type)(RandomAccessIterator);
     fptr_type x = &stable_sort_constraints;
     ...
@@ -54,8 +76,10 @@ members of the concept checking class.
 
 
   template <class Iter>
-  struct RandomAccessIterator_concept {
-    void constraints() {
+  struct RandomAccessIterator_concept
+  {
+    void constraints()
+    {
       i += n;
       ...
     }
@@ -78,10 +102,10 @@ href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
 RandomAccessIterator.
 
 
-  template <class RandomAccessIter>
-  void stable_sort(RandomAccessIter first, RandomAccessIter last)
+  template <class Iter>
+  void stable_sort(Iter first, Iter last)
   {
-    function_requires< RandomAccessIteratorConcept >();
+    function_requires< RandomAccessIteratorConcept<Iter> >();
     ...
   }
 
@@ -96,7 +120,7 @@ the concept's valid expressions. We then assign x to everything in a do-while loop to prevent name collisions.
-  template 
+  template <class Concept>
   void function_requires()
   {
     void (Concept::*x)() = BOOST_FPTR Concept::constraints;
@@ -104,6 +128,36 @@ everything in a do-while loop to prevent name collisions.
   }
 
+To check the type parameters of class templates, we provide the +BOOST_CLASS_REQUIRES 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_REQUIRES(type_var, concept) \
+  typedef void (concept <type_var>::* func##type_var##concept)(); \
+  template <func##type_var##concept _Tp1> \
+  struct concept_checking_##type_var##concept { }; \
+  typedef concept_checking_##type_var##concept< \
+    BOOST_FPTR concept <type_var>::constraints> \
+    concept_checking_typedef_##type_var##concept
+
+ +In addition, there are versions of BOOST_CLASS_REQUIRES that +take more arguments, to handle concepts that include interactions +between two or more types. BOOST_CLASS_REQUIRES was not used +in the implementation of the BCCL concept checks because several +compilers do not implement template parameters of function pointer +type. + + + + +

+Next: Reference
+Prev: Programming With Concepts + +
+


+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/prog_with_concepts.htm b/prog_with_concepts.htm index 0cc329a..afd8746 100644 --- a/prog_with_concepts.htm +++ b/prog_with_concepts.htm @@ -1,3 +1,23 @@ + + + +Programming With Concepts + +C++ Boost + +

Programming with Concepts

@@ -31,6 +51,9 @@ 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. + +

Minimality in concepts is a property associated with the underlying semantics of the problem domain being represented. In the problem @@ -104,3 +129,20 @@ 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 + +
+


+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/reference.htm b/reference.htm index b908214..212d568 100644 --- a/reference.htm +++ b/reference.htm @@ -1,9 +1,30 @@ + + + +Boost Concept Checking Reference + + +C++ Boost + +

Reference

  1. Functions
  2. -
  3. Classes
  4. +
  5. Macros
  6. Basic Concept Checking Classes
  7. Iterator Concept Checking Classes
  8. Function Object Concept Checking Classes
  9. @@ -21,55 +42,53 @@ void function_requires();
-

Classes

-
-  template <class Concept>
-  struct class_requires {
-    typedef ... check;
-  };
-
+

Macros

-  // Make sure that Type1 and Type2 are exactly the same type.
-  // If they are not, then the nested typedef for type will
-  // not exist and cause a compiler error.
-  template <class Type1, class Type2>
-  struct require_same {
-    typedef ... type;
-  };
-  // usage example
-  typedef typedef require_same::type req1; // this will compile OK
-  typedef typedef require_same::type req1; // this will cause a compiler error
+  // 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);
 
+

Basic Concept Checking Classes

   template <class T> struct Integer_concept; // Is T a built-in integer type?
   template <class T> struct SignedIntegerConcept; // Is T a built-in signed integer type?
   template <class X, class Y> struct ConvertibleConcept; // Is X convertible to Y?
-  template <class T> struct AssignableConcept;
-  template <class T> struct DefaultConstructibleConcept;
-  template <class T> struct CopyConstructibleConcept;
-  template <class T> struct BooleanConcept;
-  template <class T> struct EqualityComparableConcept;
-  // Is class T equality comparable on the left side with type Left?
-  template <class T, class Left> struct LeftEqualityComparableConcept;
-  template <class T> struct LessThanComparableConcept;
+  template <class T> struct AssignableConcept; // Standard ref 23.1
+  template <class T> struct SGIAssignableConcept;
+  template <class T> struct DefaultConstructibleConcept;
+  template <class T> struct CopyConstructibleConcept; // Standard ref 20.1.3
+  template <class T> struct EqualityComparableConcept; // Standard ref 20.1.1
+  template <class T> struct LessThanComparableConcept; // Standard ref 20.1.2
+  template <class T> struct ComparableConcept; // The SGI STL LessThanComparable concept
 

Iterator Concept Checking Classes

-  template <class Iter> struct TrivialIteratorConcept;
+  template <class Iter> struct TrivialIteratorConcept;
   template <class Iter> struct Mutable_TrivialIteratorConcept;
-  template <class Iter> struct InputIteratorConcept;
-  template <class Iter, class T> struct OutputIteratorConcept;
-  template <class Iter> struct ForwardIteratorConcept;
+  template <class Iter> struct InputIteratorConcept; // Standard ref 24.1.1 Table 72
+  template <class Iter, class T> struct OutputIteratorConcept; // Standard ref 24.1.2 Table 73
+  template <class Iter> struct ForwardIteratorConcept; // Standard ref 24.1.3 Table 74
   template <class Iter> struct Mutable_ForwardIteratorConcept;
-  template <class Iter> struct BidirectionalIteratorConcept;
+  template <class Iter> struct BidirectionalIteratorConcept; // Standard ref 24.1.4 Table 75
   template <class Iter> struct Mutable_BidirectionalIteratorConcept;
-  template <class Iter> struct RandomAccessIteratorConcept;
+  template <class Iter> struct RandomAccessIteratorConcept; // Standard ref 24.1.5 Table 76
   template <class Iter> struct Mutable_RandomAccessIteratorConcept;
 
@@ -87,23 +106,23 @@

Container Concept Checking Classes

-  template <class C> struct ContainerConcept;
+  template <class C> struct ContainerConcept; // Standard ref 23.1 Table 65
   template <class C> struct Mutable_ContainerConcept;
 
   template <class C> struct ForwardContainerConcept;
   template <class C> struct Mutable_ForwardContainerConcept;
 
-  template <class C> struct ReversibleContainerConcept;
+  template <class C> struct ReversibleContainerConcept; // Standard ref 23.1 Table 66
   template <class C> struct Mutable_ReversibleContainerConcept;
 
   template <class C> struct RandomAccessContainerConcept;
   template <class C> struct Mutable_RandomAccessContainerConcept;
 
-  template <class C> struct SequenceConcept;
+  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;
+  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;
@@ -115,11 +134,10 @@
 

Basic Archetype Classes

-  class null_archetype; // A type that models no concepts.
+  template <class T = int> class null_archetype; // A type that models no concepts.
   template <class Base = null_archetype> class default_constructible_archetype;
   template <class Base = null_archetype> class assignable_archetype;
   template <class Base = null_archetype> class copy_constructible_archetype;
-  template <class Left, class Base = null_archetype> class left_equality_comparable_archetype;
   template <class Base = null_archetype> class equality_comparable_archetype;
   template <class T, class Base = null_archetype> class convertible_to_archetype;
 
@@ -150,3 +168,20 @@ UNDER CONSTRUCTION
+

+Back to Introduction +
+Prev: Implementation + +
+


+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/using_concept_check.htm b/using_concept_check.htm index e948580..ab247d8 100644 --- a/using_concept_check.htm +++ b/using_concept_check.htm @@ -1,29 +1,74 @@ + + + +Using Concept Checks + +C++ Boost + +
+ +

Using Concept Checks

For each concept there is a concept checking class which can be used to make sure that a given type (or set of types) models the concept. -The Boost Concept Checking Library includes concept checking classes +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 below lists these +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. An example of one of these classes is the -EqualityComparableConcept class. +libraries. For example, there are graph concepts and property map concepts. +Also, whenever anyone writing a class of function template +needs to express requirements that are not yet stated by an existing +concept, a new concept checking class should be created. How +to do this is explained in Creating +Concept Checking Classes. + +

+An example of a concept checking class from the BCCL is the +EqualityComparableConcept class. The class corresponds to the +EqualityComparable requirements described in 20.1.1 of the C++ +Standard, and to the EqualityComparable +concept documented in the SGI STL.

-  template <class T> struct EqualityComparableConcept;
+  template <class T>
+  struct EqualityComparableConcept;
 
+The template argument T will the type to be checked. That is, +the purpose of EqualityComparableConcept is to make sure that +the template argument given for T models the +EqualityComparable concept. + +

Each concept checking class has a member function named constraints() which contains the valid expressions for the -concept. To check whether some type, say foo, is -EqualityComparable, we need to instantiate the concept checking class -with foo: EqualityComparableConcept<foo> and then find -a way to get the compiler to compile the constraints() -function without actually calling it. The Boost Concept Checking +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_REQUIRES. -function_requires() function can be used in function bodies + +

function_requires()

+ +The function_requires() function can be used in function bodies and the BOOST_CLASS_REQUIRES 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 @@ -31,25 +76,62 @@ means that the instantiated concept checking class must be given as an explicit template argument, as shown below.
-  void some_function_using_foo() {
-    function_requires< EqualityComparableConcept<foo> >();
+  // In my library:
+  template <class T>
+  void generic_library_function(T x)
+  {
+    function_requires< EqualityComparableConcept<T> >();
     // ...
   };
+
+  // In the user's code:  
+  class foo {
+    //... 
+  };
+
+  int main() {
+    foo f;
+    generic_library_function(f);
+    return 0;
+  }
 
+ +

BOOST_CLASS_REQUIRES

+ The BOOST_CLASS_REQUIRES macro can be used inside a class definition to check whether some type models a concept.
-  struct some_class_using_foo {
-    BOOST_CLASS_REQUIRES(foo, EqualityComparableConcept);
+  // In my library:
+  template <class T>
+  struct generic_library_class
+  {
+    BOOST_CLASS_REQUIRES(T, EqualityComparableConcept);
+    // ...
   };
+
+  // In the user's code:  
+  class foo {
+    //... 
+  };
+
+  int main() {
+    generic_library_class<foo> glc;
+    // ...
+    return 0;
+  }
 
-To add concept checks to the std::stable_sort() function the -library implementor would simply insert function_requires() -at the top of std::stable_sort() to make sure the template -parameter type models Example + +

+Getting back to the earlier motivating example, +one good applicatino 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 @@ -122,60 +204,22 @@ 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. The file is listed here: +href="./stl_concept_check.cpp">stl_concept_checks.cpp +gives and example of applying the concept checks to STL containers. -

-  #include <boost/concept_check.hpp>
+

+Prev: Concept Checking Introduction
+Next: Creating Concept Checking Classes - #include <iterator> - #include <set> - #include <map> - #include <vector> - #include <list> - #include <deque> - - int - main() - { - typedef std::vector<int> Vector; - typedef std::deque<int> Deque; - typedef std::list<int> List; - - function_requires< Mutable_RandomAccessContainer<Vector> >(); - function_requires< BackInsertionSequence<Vector> >(); - - function_requires< Mutable_RandomAccessContainer<Deque> >(); - function_requires< FrontInsertionSequence<Deque> >(); - function_requires< BackInsertionSequence<Deque> >(); - - function_requires< Mutable_ReversibleContainer<List> >(); - function_requires< FrontInsertionSequence<List> >(); - function_requires< BackInsertionSequence<List> >(); - - typedef std::set<int> Set; - typedef std::multiset<int> MultiSet; - typedef std::map<int,int> Map; - typedef std::multimap<int,int> MultiMap; - - function_requires< SortedAssociativeContainer<Set> >(); - function_requires< SimpleAssociativeContainer<Set> >(); - function_requires< UniqueAssociativeContainer<Set> >(); - - function_requires< SortedAssociativeContainer<MultiSet> >(); - function_requires< SimpleAssociativeContainer<MultiSet> >(); - function_requires< MultipleAssociativeContainer<MultiSet> >(); - - function_requires< SortedAssociativeContainer<Map> >(); - function_requires< UniqueAssociativeContainer<Map> >(); - function_requires< PairAssociativeContainer<Map> >(); - - function_requires< SortedAssociativeContainer<MultiMap> >(); - function_requires< MultipleAssociativeContainer<MultiMap> >(); - function_requires< PairAssociativeContainer<MultiMap> >(); - - return 0; - } -

+
+
+ + +
Copyright © 2000 +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ +