From 90b0397f5435919858c6dce444671576cd3bd7df Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 8 Feb 2014 20:31:42 -0800 Subject: [PATCH] Remove out-dated/unused/duplicate files. --- bibliography.html | 70 -- class_concept_checks_fail_expected.cpp | 30 - class_concept_checks_test.cpp | 37 - concept_checking.html | 999 ------------------------- concept_checks_fail_expected.cpp | 23 - concept_checks_test.cpp | 185 ----- stl_concept_checks.cpp | 90 --- stl_concept_checks.expected | 0 8 files changed, 1434 deletions(-) delete mode 100644 bibliography.html delete mode 100644 class_concept_checks_fail_expected.cpp delete mode 100644 class_concept_checks_test.cpp delete mode 100644 concept_checking.html delete mode 100644 concept_checks_fail_expected.cpp delete mode 100644 concept_checks_test.cpp delete mode 100644 stl_concept_checks.cpp delete mode 100644 stl_concept_checks.expected diff --git a/bibliography.html b/bibliography.html deleted file mode 100644 index 554a3a5..0000000 --- a/bibliography.html +++ /dev/null @@ -1,70 +0,0 @@ - - - -Boost Graph Library: Bibliography - -C++ Boost - -
- - -

Bibliography

- -
- -

1 -
Andrei Alexandrescu
-Better Template Error Messages.
-C/C++ Users Journal, March, 1999. - - -

2 -
Bjarne Stroustrup
-Design and Evolution of C++.
-Addison-Wesley, 1994 - -

3 -
-M. H. Austern. -
Generic Programming and the STL. -
Professional computing series. Addison-Wesley, 1999. - -

4 -
-David R. Musser and Atul Saini -
STL Tutorial and Reference Guide. -
Professional computing series. Addison-Wesley, 1996. - -

5 -
-A. A. Stepanov and M. Lee -
The Standard Template Library. -
ISO Programming Language C++ Project, May 1994. -
X3J16/94-0095, WG21/N0482 - - - -
- -
-
- - -
Copyright © 2000 -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) -
- - - diff --git a/class_concept_checks_fail_expected.cpp b/class_concept_checks_fail_expected.cpp deleted file mode 100644 index 24743d6..0000000 --- a/class_concept_checks_fail_expected.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, -// sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include - -/* - - This file verifies that class_requires of the Boost Concept Checking - Library catches errors when it is suppose to. - -*/ - -struct foo { }; - -using namespace boost; - -class class_requires_test -{ - BOOST_CLASS_REQUIRES(foo, EqualityComparableConcept); -}; - -int -main() -{ - class_requires_test x; - return 0; -} diff --git a/class_concept_checks_test.cpp b/class_concept_checks_test.cpp deleted file mode 100644 index 2eb3cce..0000000 --- a/class_concept_checks_test.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, -// sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include - -/* - - This file verifies that the BOOST_CLASS_REQUIRES macro of the Boost - Concept Checking Library does not cause errors when it is not suppose - to. - -*/ - -struct foo { bool operator()(int) { return true; } }; -struct bar { bool operator()(int, char) { return true; } }; - -using namespace boost; - -class class_requires_test -{ - BOOST_CLASS_REQUIRES(int, EqualityComparableConcept); - typedef int* int_ptr; typedef const int* const_int_ptr; - BOOST_CLASS_REQUIRES2(int_ptr, const_int_ptr, Comparable2Concept); - BOOST_CLASS_REQUIRES3(foo, bool, int, UnaryFunctionConcept); - BOOST_CLASS_REQUIRES4(bar, bool, int, char, BinaryFunctionConcept); -}; - -int -main() -{ - class_requires_test x; - ignore_unused_variable_warning(x); - return 0; -} diff --git a/concept_checking.html b/concept_checking.html deleted file mode 100644 index d658842..0000000 --- a/concept_checking.html +++ /dev/null @@ -1,999 +0,0 @@ - - - -Concept Checking - -C++ Boost - -
- -

- -header -boost/concept_checks.hpp and -boost/concept_archetypes.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. - -The documentation is organized into the following sections. - -

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

-Jeremy Siek -contributed this library. X managed the formal review. - -

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  struct foo {
-   5    bool operator<(const foo&) const { return false; }
-   6  };
-   7  int main(int, char*[]) {
-   8    std::list<foo> v;
-   9    std::stable_sort(v.begin(), v.end());
-  10    return 0;
-  11  }
-
- -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
-  <foo,foo &,foo *>, foo *, int>(_List_iterator<foo,foo &,foo *>,
-  _List_iterator<foo,foo &,foo *>, foo *, int)':
-stl_algo.h:1448:   instantiated from `__merge_sort_with_buffer
-  <_List_iterator<foo,foo &,foo *>, foo *, int>(
-   _List_iterator<foo,foo &,foo *>, _List_iterator<foo,foo &,foo *>,
-   foo *, int *)'
-stl_algo.h:1485:   instantiated from `__stable_sort_adaptive<
-  _List_iterator<foo,foo &,foo *>, foo *, int>(_List_iterator
-  <foo,foo &,foo *>, _List_iterator<foo,foo &,foo *>, foo *, int)'
-stl_algo.h:1524:   instantiated from here
-stl_algo.h:1377: no match for `_List_iterator<foo,foo &,foo *> & -
-  _List_iterator<foo,foo &,foo *> &'
-
- -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. - -

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

    -
  1. The location of the error, line 9 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. -
- -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): - -
-concept_checks.hpp: In method `void LessThanComparable_concept
-  <_List_iterator<foo,foo &,foo *> >::constraints()':
-concept_checks.hpp:334:   instantiated from `RandomAccessIterator_concept
-  <_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_checks.hpp:209: no match for `_List_iterator<foo,foo &,foo *> &
-  < _List_iterator<foo,foo &,foo *> &'
-
- -This message rectifies several of the shortcomings of the standard -error messages. - -
    -
  • The location of the error, bad_error_eg.cpp:9 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_checks.hpp and - constraints() in the error message alerts the user to the - fact that the error lies in the user code and not in the library - implementation. -
- - -

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 -for all of the concepts used in the C++ standard library and a few -more. The Reference section below 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. - -
-  template <class T> struct EqualityComparableConcept;
-
- -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 -Library defines two utilities that make this easy: -function_requires() and BOOST_CLASS_REQUIRES. -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 -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> >();
-    // ...
-  };
-
- -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);
-  };
-
- -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 -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 -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> >();
-    ...
-  }
-
- - -As an example of using class_requires 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 {
-      typedef typename class_requires< AssignableConcept<T> >::check req;
-      ...
-    };
-  }
-
- - -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. The file is listed here: - -
-  #include <boost/concept_checks.hpp>
-
-  #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;
-  }
-
- - -

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''. Note that the REQUIRE macro expects -the suffix to be there. Next we must define a member function named -constraints() in which we will exercise the valid expressions -of the concept. The REQUIRE macro expects this function's -signature to appear exactly as it is appears below: a void -non-const member function with no parameters. - -

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

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

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

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 TrivialIterator -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 input_proxy. 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>
-  struct input_proxy {
-    operator T() { return t; }
-    static T t;
-  };
-  template <class T>
-  class trivial_iterator_archetype
-  {
-    typedef trivial_iterator_archetype self;
-  public:
-    trivial_iterator_archetype() { }
-    trivial_iterator_archetype(const self&) { }
-    self& operator=(const self&) { return *this;  }
-    friend bool operator==(const self&, const self&) { return true; }
-    friend bool operator!=(const self&, const self&) { return true; }
-    input_proxy<T> operator*() { return input_proxy<T>(); }
-  };
-
-  namespace std {
-    template <class T>
-    struct iterator_traits< trivial_iterator_archetype<T> >
-    {
-      typedef T value_type;
-    };
-  }
-
- -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. - -

-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< 
-      copy_constructible_archetype<
-        assignable_archetype<> > > ValueType;
-    random_access_iterator_archetype<ValueType> ri;
-    std::stable_sort(ri, ri);
-  }
-
- - -

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

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

-There is natural tension in this statement. By definition, the input -parameters must be used by the component in order for the component to -accomplish its task (by ``component'' we mean a function or class -template). The challenge then is to implement the component in such a -way that makes the fewest assumptions (the minimum requirements) about -the inputs while still accomplishing the task. - -

-The traditional notions of abstraction tie in directly to the -idea of minimal requirements. The more abstract the input, the fewer -the requirements. Thus, concepts are simply the embodiment of generic -abstract data types in C++ template programming. - -

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

-It is important to note, however, that -minimizing concepts does not mean simply -reducing the number of valid expressions -in the concept. -For example, the -std::stable_sort() function requires that the value type of -the iterator be -LessThanComparable, which not only -includes operator<(), but also operator>(), -operator<=(), and operator>=(). -It turns out that std::stable_sort() only uses -operator<(). The question then arises: should -std::stable_sort() be specified in terms of the concept - -LessThanComparable or in terms of a concept that only -requires operator<()? - -

-We remark first that the use of -LessThanComparable does not really violate the requirement -minimization principle because all of the other operators can be -trivially implemented in terms of operator<(). By -``trivial'' we mean one line of code and a constant run-time cost. -More fundamentally, however, the use of -LessThanComparable does not violate the requirement minimization -principle because all of the comparison operators (<, ->, <=, >=) are conceptually equivalent (in -a mathematical sense). Adding conceptually equivalent valid -expressions is not a violation of the requirement minimization -principle because no new semantics are being added --- only new -syntax. The added syntax increases re-usability. - -

-For example, -the -maintainer of the std::stable_sort() may some day change the -implementation in places to use operator>() instead of -operator<(), since, after all, they are equivalent. Since the -requirements are part of the public interface, such a change could -potentially break client code. If instead - -LessThanComparable is given as the requirement for -std::stable_sort(), then the maintainer is given a reasonable -amount of flexibility within which to work. - -

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

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) {
-    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) {
-    typedef void (*fptr_type)(RandomAccessIterator);
-    fptr_type x = &stable_sort_constraints;
-    ...
-  }
-
- -There is often a large set of requirements that need to be checked, -and it would be cumbersome for the library implementor to write -constraint functions like stable_sort_constraints() for every -public function. Instead, we group sets of valid expressions -together, according to the definitions of the corresponding concepts. -For each concept we define a concept checking class template where the -template parameter is for the type to be checked. The class contains -a contraints() member function which exercises all of the -valid expressions of the concept. The objects used in the constraints -function, such as n and i, are declared as data -members of the concept checking class. - -
-  template <class Iter>
-  struct RandomAccessIterator_concept {
-    void constraints() {
-      i += n;
-      ...
-    }
-    typename std::iterator_traits<RandomAccessIterator>
-      ::difference_type n;
-    Iter i;
-    ...
-  };
-
- -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 RandomAccessIter>
-  void stable_sort(RandomAccessIter first, RandomAccessIter last)
-  {
-    function_requires< RandomAccessIteratorConcept >();
-    ...
-  }
-
- -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 
-  void function_requires()
-  {
-    void (Concept::*x)() = BOOST_FPTR Concept::constraints;
-    ignore_unused_variable_warning(x);
-  }
-
- -To check the type parameters of class templates, we provide the -class_requires class which can be used inside the body of a -class definition (whereas function_requires() can only be -used inside of a function body). class_requires 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. - -
-  template <class Concept>
-  class class_requires
-  {
-    typedef void (Concept::* function_pointer)();
-
-    template <function_pointer Fptr>
-    struct dummy_struct { };
-  public:
-    typedef dummy_struct< BOOST_FPTR Concept::constraints > check;
-  };
-
- -class_requires was not used in the implementation of the -Boost Concept Checking Library concept checks because several -compilers do not implement template parameters of function pointer -type. - - - -

Reference

- - -

Functions

- -
-  template <class Concept>
-  void function_requires();
-
- -

Classes

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

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

Iterator Concept Checking Classes

- -
-  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 Mutable_ForwardIteratorConcept;
-  template <class Iter> struct BidirectionalIteratorConcept;
-  template <class Iter> struct Mutable_BidirectionalIteratorConcept;
-  template <class Iter> struct RandomAccessIteratorConcept;
-  template <class Iter> struct Mutable_RandomAccessIteratorConcept;
-
- -

Function Object Concept Checking Classes

- -
-  template <class Func, class Return> struct GeneratorConcept;
-  template <class Func, class Return, class Arg> struct UnaryFunctionConcept;
-  template <class Func, class Return, class First, class Second> struct BinaryFunctionConcept;
-  template <class Func, class Arg> struct UnaryPredicateConcept;
-  template <class Func, class First, class Second> struct BinaryPredicateConcept;
-  template <class Func, class First, class Second> struct Const_BinaryPredicateConcept {;
-
- -

Container Concept Checking Classes

- -
-  template <class C> struct ContainerConcept;
-  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 Mutable_ReversibleContainerConcept;
-
-  template <class C> struct RandomAccessContainerConcept;
-  template <class C> struct Mutable_RandomAccessContainerConcept;
-
-  template <class C> struct SequenceConcept;
-  template <class C> struct FrontInsertionSequenceConcept;
-  template <class C> struct BackInsertionSequenceConcept;
-
-  template <class C> struct AssociativeContainerConcept;
-  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;
-
- - -

Basic Archetype Classes

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

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

- -
-UNDER CONSTRUCTION
-
- -

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. - -
-
- - -
Copyright © 2000 -Jeremy Siek, -Univ.of Notre Dame (jsiek@lsc.nd.edu) -
- - - diff --git a/concept_checks_fail_expected.cpp b/concept_checks_fail_expected.cpp deleted file mode 100644 index a646746..0000000 --- a/concept_checks_fail_expected.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, -// sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include - -/* - - This file verifies that function_requires() of the Boost Concept - Checking Library catches errors when it is suppose to. - -*/ - -struct foo { }; - -int -main() -{ - boost::function_requires< boost::EqualityComparableConcept >(); - return 0; -} diff --git a/concept_checks_test.cpp b/concept_checks_test.cpp deleted file mode 100644 index b5fc58b..0000000 --- a/concept_checks_test.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, -// sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -#include -#include - -/* - - This file verifies that the BOOST_FUNCTION_REQUIRES macros of the - Boost Concept Checking Library do not cause errors when they are not - suppose to and verifies that the concept archetypes meet the - requirements of their matching concepts. - -*/ - - -int -main() -{ - using namespace boost; - - //=========================================================================== - // Basic Concepts - { - typedef default_constructible_archetype<> foo; - function_requires< DefaultConstructibleConcept >(); - } - { - typedef assignable_archetype<> foo; - function_requires< AssignableConcept >(); - } - { - typedef copy_constructible_archetype<> foo; - function_requires< CopyConstructibleConcept >(); - } - { - typedef sgi_assignable_archetype<> foo; - function_requires< SGIAssignableConcept >(); - } - { - typedef copy_constructible_archetype<> foo; - typedef convertible_to_archetype convertible_to_foo; - function_requires< ConvertibleConcept >(); - } - { - function_requires< ConvertibleConcept >(); - } - { - typedef equality_comparable_archetype<> foo; - function_requires< EqualityComparableConcept >(); - } - { - typedef less_than_comparable_archetype<> foo; - function_requires< LessThanComparableConcept >(); - } - { - typedef comparable_archetype<> foo; - function_requires< ComparableConcept >(); - } - { - typedef equal_op_first_archetype<> First; - typedef equal_op_second_archetype<> Second; - function_requires< EqualOpConcept >(); - } - { - typedef not_equal_op_first_archetype<> First; - typedef not_equal_op_second_archetype<> Second; - function_requires< NotEqualOpConcept >(); - } - { - typedef less_than_op_first_archetype<> First; - typedef less_than_op_second_archetype<> Second; - function_requires< LessThanOpConcept >(); - } - { - typedef less_equal_op_first_archetype<> First; - typedef less_equal_op_second_archetype<> Second; - function_requires< LessEqualOpConcept >(); - } - { - typedef greater_than_op_first_archetype<> First; - typedef greater_than_op_second_archetype<> Second; - function_requires< GreaterThanOpConcept >(); - } - { - typedef greater_equal_op_first_archetype<> First; - typedef greater_equal_op_second_archetype<> Second; - function_requires< GreaterEqualOpConcept >(); - } - - { - typedef copy_constructible_archetype<> Return; - typedef plus_op_first_archetype First; - typedef plus_op_second_archetype Second; - function_requires< PlusOpConcept >(); - } - - //=========================================================================== - // Function Object Concepts - - { - typedef generator_archetype > foo; - function_requires< GeneratorConcept > >(); - } - { - function_requires< GeneratorConcept< void_generator_archetype, void > >(); - } - { - typedef unary_function_archetype F; - function_requires< UnaryFunctionConcept >(); - } - { - typedef binary_function_archetype F; - function_requires< BinaryFunctionConcept >(); - } - { - typedef unary_predicate_archetype F; - function_requires< UnaryPredicateConcept >(); - } - { - typedef binary_predicate_archetype F; - function_requires< BinaryPredicateConcept >(); - typedef const_binary_predicate_archetype const_F; - function_requires< Const_BinaryPredicateConcept >(); - } - - //=========================================================================== - // Iterator Concepts - { - typedef trivial_iterator_archetype > Iter; - function_requires< TrivialIteratorConcept >(); - } - { - typedef mutable_trivial_iterator_archetype > Iter; - function_requires< Mutable_TrivialIteratorConcept >(); - } - { - typedef input_iterator_archetype > Iter; - function_requires< InputIteratorConcept >(); - } - { - typedef output_iterator_archetype Iter; - function_requires< OutputIteratorConcept >(); - } - { - typedef forward_iterator_archetype > Iter; - function_requires< ForwardIteratorConcept >(); - } - { - typedef forward_iterator_archetype > Iter; - function_requires< Mutable_ForwardIteratorConcept >(); - } - { - typedef bidirectional_iterator_archetype > Iter; - function_requires< BidirectionalIteratorConcept >(); - } - { - typedef bidirectional_iterator_archetype > Iter; - function_requires< Mutable_BidirectionalIteratorConcept >(); - } - { - typedef random_access_iterator_archetype > Iter; - function_requires< RandomAccessIteratorConcept >(); - } - { - typedef random_access_iterator_archetype > Iter; - function_requires< Mutable_RandomAccessIteratorConcept >(); - } - - //=========================================================================== - // Container Concepts - - { - - function_requires< ContainerConcept< > >(); - } - { - - } - - return 0; -} diff --git a/stl_concept_checks.cpp b/stl_concept_checks.cpp deleted file mode 100644 index 0bcfad2..0000000 --- a/stl_concept_checks.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, -// sell and distribute this software is granted provided this -// copyright notice appears in all copies. This software is provided -// "as is" without express or implied warranty, and with no claim as -// to its suitability for any purpose. - -// -// This file checks to see if various standard container -// implementations live up to requirements specified in the C++ -// standard. As many implementations do not live to the requirements, -// it is not uncommon for this file to fail to compile. The -// BOOST_HIDE_EXPECTED_ERRORS macro is provided here if you want to -// see as much of this file compile as possible. -// - -#include - -#include -#include -#include -#include -#include -#include -#ifndef BOOST_NO_SLIST -#include -#endif - -//#define BOOST_HIDE_EXPECTED_ERRORS - -int -main() -{ - using namespace boost; - -#if defined(_ITERATOR_) && defined(BOOST_HIDE_EXPECTED_ERRORS) - // VC++ STL implementation is not standard conformant and - // fails to pass these concept checks -#else - typedef std::vector Vector; - typedef std::deque Deque; - typedef std::list List; - - // VC++ missing pointer and const_pointer typedefs - function_requires< Mutable_RandomAccessContainerConcept >(); - function_requires< BackInsertionSequenceConcept >(); - -#if !(defined(__GNUC__) && defined(BOOST_HIDE_EXPECTED_ERRORS)) -#if !(defined(__sgi) && defined(BOOST_HIDE_EXPECTED_ERRORS)) - // old deque iterator missing n + iter operation - function_requires< Mutable_RandomAccessContainerConcept >(); -#endif - // warnings about signed and unsigned in old deque version - function_requires< FrontInsertionSequenceConcept >(); - function_requires< BackInsertionSequenceConcept >(); -#endif - - // VC++ missing pointer and const_pointer typedefs - function_requires< Mutable_ReversibleContainerConcept >(); - function_requires< FrontInsertionSequenceConcept >(); - function_requires< BackInsertionSequenceConcept >(); - -#ifndef BOOST_NO_SLIST - typedef std::slist SList; - function_requires< FrontInsertionSequenceConcept >(); -#endif - - typedef std::set Set; - typedef std::multiset MultiSet; - typedef std::map Map; - typedef std::multimap MultiMap; - - function_requires< SortedAssociativeContainerConcept >(); - function_requires< SimpleAssociativeContainerConcept >(); - function_requires< UniqueAssociativeContainerConcept >(); - - function_requires< SortedAssociativeContainerConcept >(); - function_requires< SimpleAssociativeContainerConcept >(); - function_requires< MultipleAssociativeContainerConcept >(); - - function_requires< SortedAssociativeContainerConcept >(); - function_requires< UniqueAssociativeContainerConcept >(); - function_requires< PairAssociativeContainerConcept >(); - - function_requires< SortedAssociativeContainerConcept >(); - function_requires< MultipleAssociativeContainerConcept >(); - function_requires< PairAssociativeContainerConcept >(); -#endif - - return 0; -} diff --git a/stl_concept_checks.expected b/stl_concept_checks.expected deleted file mode 100644 index e69de29..0000000