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 @@
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: +
+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.
-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. +
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) |
Copyright © 2000 | +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) + |
+Next: Concept Covering and Archetypes
+Prev: Using Concept Checks
+
+
+
+
Copyright © 2000 | +Jeremy Siek, +Univ.of Notre Dame (jsiek@lsc.nd.edu) + |
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@@ -96,7 +120,7 @@ the concept's valid expressions. We then assign x to everything in a do-while loop to prevent name collisions.>(); + function_requires< RandomAccessIteratorConcept<Iter> >(); ... } - template+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. + ++ 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. } +#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) + |
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) + |
- template <class Concept> - struct class_requires { - typedef ... check; - }; -+
- // 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);
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
- 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 @@
- 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) + |
+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 + +
- 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; + }+ +
- 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) + |