Compare commits

...

2 Commits

Author SHA1 Message Date
07fec6e1e4 This commit was manufactured by cvs2svn to create tag
'Version_1_28_0'.

[SVN r13949]
2002-05-16 13:26:18 +00:00
93810857db This commit was manufactured by cvs2svn to create branch 'RC_1_28_0'.
[SVN r13795]
2002-05-10 04:34:27 +00:00
8 changed files with 0 additions and 1434 deletions

View File

@ -1,70 +0,0 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Boost Graph Library: Bibliography</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<BR Clear>
<H2>Bibliography</H2>
<DL COMMapCT>
<DD><P></P><DT><a name="alexandrescu99:_better_templ_error_messag">1</a>
<DD>Andrei Alexandrescu<BR>
<EM>Better Template Error Messages</EM>.<BR>
C/C++ Users Journal, March, 1999.
<DD><P></P><DT><a name="stroustrup94:_design_evolution">2</a>
<DD>Bjarne Stroustrup<BR>
<EM>Design and Evolution of C++</EM>.<BR>
Addison-Wesley, 1994
<P></P><DT><A NAME="austern99:_gener_progr_stl">3</A>
<DD>
M.&nbsp;H. Austern.
<BR><EM>Generic Programming and the STL</EM>.
<BR>Professional computing series. Addison-Wesley, 1999.
<P></P><DT><A NAME="IB-H965502">4</A>
<DD>
David R. Musser and Atul Saini
<BR><EM>STL Tutorial and Reference Guide</EM>.
<BR>Professional computing series. Addison-Wesley, 1996.
<P></P><DT><A NAME="stepa.lee-1994:the.s:TR">5</A>
<DD>
A. A. Stepanov and M. Lee
<BR><EM>The Standard Template Library</EM>.
<BR>ISO Programming Language C++ Project, May 1994.
<BR>X3J16/94-0095, WG21/N0482
</DL>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

View File

@ -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 <boost/pending/concept_checks.hpp>
/*
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;
}

View File

@ -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 <boost/pending/concept_checks.hpp>
/*
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;
}

View File

@ -1,999 +0,0 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. We make no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Concept Checking</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<BR Clear>
<H1>
<A NAME="sec:concept-checking"></A>
header <a href="../../boost/pending/concept_checks.hpp">
<tt>boost/concept_checks.hpp</tt></a> and <a href="../../boost/pending/concept_archetypes.hpp">
<tt>boost/concept_archetypes.hpp</tt></a>
</H1>
<p>
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.
<OL>
<LI><a href="#introduction">Introduction</a></LI>
<LI><a href="#motivating-example">Motivating Example</a></LI>
<LI><a href="#using-concept-checks">Using Concept Checks</a></LI>
<LI><a href="#creating-concept-checks">Creating Concept Checking Classes</a></LI>
<LI><a href="#concept-covering">Concept Covering and Archetypes</a></LI>
<LI><a href="#programming-with-concepts">Programming With Concepts</a></LI>
<LI><a href="#implementation">Implementation</a></LI>
<LI><a href="#reference">Reference</a></LI>
<OL>
<LI><a href="#functions">Functions</a></LI>
<LI><a href="#classes">Classes</a></LI>
<LI><a href="#basic-concepts">Basic Concept Checking Classes</a></LI>
<LI><a href="#iterator-concepts">Iterator Concept Checking Classes</a></LI>
<LI><a href="#function-object-concepts">Function Object Concept Checking Classes</a></LI>
<LI><a href="#container-concepts">Container Concept Checking Classes</a></LI>
<LI><a href="#basic-archetype">Basic Archetype Classes</a></LI>
<LI><a href="#iterator-archetype">Iterator Archetype Classes</a></LI>
<LI><a href="#function-object-archetype">Function Object Archetype Classes</a></LI>
<LI><a href="#container-archetype">Container Archetype Classes</a></LI>
</OL>
<LI><a href="#history">History</a></LI>
<LI><a href="#publications">Publications</a></LI>
<LI><a href="#acknowledgements">Acknowledgements</a></LI>
</OL>
<p>
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
contributed this library. X managed the formal review.
<h2><a name="introduction">Introduction</a></h2>
A <i>concept</i> 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.
<p>
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 <i>per
se</i> 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.
<p>
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.
<p>
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..
<h2><a name="motivating-example">Motivating Example</a></h2>
We present a simple example to illustrate incorrect usage of a
template library and the resulting error messages. In the code below,
the generic <tt>std::stable_sort()</tt> algorithm from the Standard
Template Library (STL)[<a
href="bibliography.html#austern99:_gener_progr_stl">3</a>, <a
href="bibliography.html#IB-H965502">4</a>,<a
href="bibliography.html#stepa.lee-1994:the.s:TR">5</a>] is applied to
a linked list.
<pre>
<a href="./bad_error_eg.cpp">bad_error_eg.cpp</a>:
1 #include &lt;list&gt;
2 #include &lt;algorithm&gt;
3
4 struct foo {
5 bool operator&lt;(const foo&) const { return false; }
6 };
7 int main(int, char*[]) {
8 std::list&lt;foo&gt; v;
9 std::stable_sort(v.begin(), v.end());
10 return 0;
11 }
</pre>
Here, the
<tt>std::stable_sort()</tt> algorithm is prototyped as follows:
<pre>
template &lt;class RandomAccessIterator&gt;
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
</pre>
Attempting to compile this code with Gnu C++ produces the following
compiler error. The output from other compilers is listed in the
Appendix.
<pre>
stl_algo.h: In function `void __merge_sort_loop&lt;_List_iterator
&lt;foo,foo &,foo *&gt;, foo *, int&gt;(_List_iterator&lt;foo,foo &,foo *&gt;,
_List_iterator&lt;foo,foo &,foo *&gt;, foo *, int)':
stl_algo.h:1448: instantiated from `__merge_sort_with_buffer
&lt;_List_iterator&lt;foo,foo &,foo *&gt;, foo *, int&gt;(
_List_iterator&lt;foo,foo &,foo *&gt;, _List_iterator&lt;foo,foo &,foo *&gt;,
foo *, int *)'
stl_algo.h:1485: instantiated from `__stable_sort_adaptive&lt;
_List_iterator&lt;foo,foo &,foo *&gt;, foo *, int&gt;(_List_iterator
&lt;foo,foo &,foo *&gt;, _List_iterator&lt;foo,foo &,foo *&gt;, foo *, int)'
stl_algo.h:1524: instantiated from here
stl_algo.h:1377: no match for `_List_iterator&lt;foo,foo &,foo *&gt; & -
_List_iterator&lt;foo,foo &,foo *&gt; &'
</pre>
In this case, the fundamental error is that
<tt>std:list::iterator</tt> does not model the concept of <a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a>. 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.
<p>
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.
<OL>
<LI> The location of the error, line 9 of <tt>bad_error_eg.cpp</tt>
is not pointed to by the error message, despite the fact that Gnu C++
prints up to 4 levels deep in the instantiation stack.
<LI> There is no textual correlation between the error message and the
documented requirements for <tt>std::stable_sort()</tt> and for
<a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a>.
<LI> The error message is overly long, listing functions internal
to the STL that the user does not (and should not!) know or care
about.
<LI> 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.
</OL>
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):
<pre>
concept_checks.hpp: In method `void LessThanComparable_concept
&lt;_List_iterator&lt;foo,foo &,foo *> >::constraints()':
concept_checks.hpp:334: instantiated from `RandomAccessIterator_concept
&lt;_List_iterator&lt;foo,foo &,foo *> >::constraints()'
bad_error_eg.cpp:9: instantiated from `stable_sort&lt;_List_iterator
&lt;foo,foo &,foo *> >(_List_iterator&lt;foo,foo &,foo *>,
_List_iterator&lt;foo,foo &,foo *>)'
concept_checks.hpp:209: no match for `_List_iterator&lt;foo,foo &,foo *> &
&lt; _List_iterator&lt;foo,foo &,foo *> &'
</pre>
This message rectifies several of the shortcomings of the standard
error messages.
<UL>
<LI> The location of the error, <tt>bad_error_eg.cpp:9</tt> is
specified in the error message.
<LI> The message refers explicitly to concepts that the user can look
up in the STL documentation (<a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a>).
<LI> The error message is now much shorter and does not reveal
internal STL functions.
<LI> The presence of <tt>concept_checks.hpp</tt> and
<tt>constraints()</tt> in the error message alerts the user to the
fact that the error lies in the user code and not in the library
implementation.
</UL>
<h2><a name="using-concept-checks">Using Concept Checks</a></h2>
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 <a href="#reference">Reference</a> 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
<tt>EqualityComparableConcept</tt> class.
<pre>
template &lt;class T&gt; struct EqualityComparableConcept;
</pre>
Each concept checking class has a member function named
<tt>constraints()</tt> which contains the valid expressions for the
concept. To check whether some type, say <tt>foo</tt>, is
EqualityComparable, we need to instantiate the concept checking class
with foo: <tt>EqualityComparableConcept&lt;foo&gt;</tt> and then find
a way to get the compiler to compile the <tt>constraints()</tt>
function without actually calling it. The Boost Concept Checking
Library defines two utilities that make this easy:
<tt>function_requires()</tt> and <tt>BOOST_CLASS_REQUIRES</tt>.
<tt>function_requires()</tt> function can be used in function bodies
and the <tt>BOOST_CLASS_REQUIRES</tt> macro can be used inside class
bodies. The <tt>function_requires()</tt> 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.
<pre>
void some_function_using_foo() {
function_requires&lt; EqualityComparableConcept&lt;foo&gt; &gt;();
// ...
};
</pre>
The <tt>BOOST_CLASS_REQUIRES</tt> macro can be used inside a class
definition to check whether some type models a concept.
<pre>
struct some_class_using_foo {
BOOST_CLASS_REQUIRES(foo, EqualityComparableConcept);
};
</pre>
To add concept checks to the <tt>std::stable_sort()</tt> function the
library implementor would simply insert <tt>function_requires()</tt>
at the top of <tt>std::stable_sort()</tt> to make sure the template
parameter type models <a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a>. In addition, <tt>std::stable_sort()</tt>
requires that the <tt>value_type</tt> of the iterators be
<a href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a>, so we also use <tt>function_requires()</tt> to
check this.
<pre>
template &lt;class RandomAccessIter&gt;
void stable_sort(RandomAccessIter first, RandomAccessIter last)
{
function_requires&lt; RandomAccessIteratorConcept&lt;RandomAccessIter&gt; &gt;();
typedef typename std::iterator_traits&lt;RandomAccessIter&gt;::value_type value_type;
function_requires&lt; LessThanComparableConcept&lt;value_type&gt; &gt;();
...
}
</pre>
<!-- There are a few places where the SGI STL documentation differs
from the corresponding requirements described in the C++ Standard. In
these cases we use the definition from the C++ Standard. -->
<p>
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
<tt>function_requires()</tt> is used with the <a
href="../property_map/ReadWritePropertyMap.html">ReadWritePropertyMap</a>
concept which takes two type parameters: a property map and the key
type for the map.
<pre>
template &lt;class IncidenceGraph, class Buffer, class BFSVisitor,
class ColorMap&gt;
void breadth_first_search(IncidenceGraph& g,
typename graph_traits&lt;IncidenceGraph&gt;::vertex_descriptor s,
Buffer& Q, BFSVisitor vis, ColorMap color)
{
typedef typename graph_traits&lt;IncidenceGraph&gt;::vertex_descriptor Vertex;
function_requires&lt; ReadWritePropertyMap&lt;ColorMap, Vertex&gt; &gt;();
...
}
</pre>
As an example of using <tt>class_requires</tt> we look at a concept
check that could be added to <tt>std::vector</tt>. One requirement
that is placed on the element type is that it must be <a
href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</a>.
We can check this by inserting
<tt>class_requires&lt;AssignableConcept&lt;T&gt; &gt;</tt> at the top
of the definition for <tt>std::vector</tt>.
<pre>
namespace std {
template &lt;class T&gt;
struct vector {
typedef typename class_requires&lt; AssignableConcept&lt;T&gt; &gt;::check req;
...
};
}
</pre>
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
<tt>function_requires()</tt> with the type and concept in question.
The file <a
href="./stl_concept_checks.cpp"><tt>stl_concept_checks.cpp</tt></a>
gives and example of applying the concept checks to STL
containers. The file is listed here:
<pre>
#include &lt;boost/concept_checks.hpp&gt;
#include &lt;iterator&gt;
#include &lt;set&gt;
#include &lt;map&gt;
#include &lt;vector&gt;
#include &lt;list&gt;
#include &lt;deque&gt;
int
main()
{
typedef std::vector&lt;int&gt; Vector;
typedef std::deque&lt;int&gt; Deque;
typedef std::list&lt;int&gt; List;
function_requires&lt; Mutable_RandomAccessContainer&lt;Vector&gt; &gt;();
function_requires&lt; BackInsertionSequence&lt;Vector&gt; &gt;();
function_requires&lt; Mutable_RandomAccessContainer&lt;Deque&gt; &gt;();
function_requires&lt; FrontInsertionSequence&lt;Deque&gt; &gt;();
function_requires&lt; BackInsertionSequence&lt;Deque&gt; &gt;();
function_requires&lt; Mutable_ReversibleContainer&lt;List&gt; &gt;();
function_requires&lt; FrontInsertionSequence&lt;List&gt; &gt;();
function_requires&lt; BackInsertionSequence&lt;List&gt; &gt;();
typedef std::set&lt;int&gt; Set;
typedef std::multiset&lt;int&gt; MultiSet;
typedef std::map&lt;int,int&gt; Map;
typedef std::multimap&lt;int,int&gt; MultiMap;
function_requires&lt; SortedAssociativeContainer&lt;Set&gt; &gt;();
function_requires&lt; SimpleAssociativeContainer&lt;Set&gt; &gt;();
function_requires&lt; UniqueAssociativeContainer&lt;Set&gt; &gt;();
function_requires&lt; SortedAssociativeContainer&lt;MultiSet&gt; &gt;();
function_requires&lt; SimpleAssociativeContainer&lt;MultiSet&gt; &gt;();
function_requires&lt; MultipleAssociativeContainer&lt;MultiSet&gt; &gt;();
function_requires&lt; SortedAssociativeContainer&lt;Map&gt; &gt;();
function_requires&lt; UniqueAssociativeContainer&lt;Map&gt; &gt;();
function_requires&lt; PairAssociativeContainer&lt;Map&gt; &gt;();
function_requires&lt; SortedAssociativeContainer&lt;MultiMap&gt; &gt;();
function_requires&lt; MultipleAssociativeContainer&lt;MultiMap&gt; &gt;();
function_requires&lt; PairAssociativeContainer&lt;MultiMap&gt; &gt;();
return 0;
}
</pre>
<h2><a name="creating-concept-checks">Creating Concept Checking Classes</a></h2>
As an example of how to create a concept checking class, we look
at how to create the corresponding checks for the
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a> concept. First, as a convention we name the
concept checking class after the concept, and add the suffix
``<tt>_concept</tt>''. Note that the <tt>REQUIRE</tt> macro expects
the suffix to be there. Next we must define a member function named
<tt>constraints()</tt> in which we will exercise the valid expressions
of the concept. The <tt>REQUIRE</tt> macro expects this function's
signature to appear exactly as it is appears below: a <tt>void</tt>
non-const member function with no parameters.
<p>
The first part of the <tt>constraints()</tt> function includes
the requirements that correspond to the <i>refinement</i> relationship
between <a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a> and the concepts which it builds upon:
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
BidirectionalIterator</a> and
<a href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a>. We could have instead used
<tt>CLASS_REQUIRES</tt> and placed these requirements in the class
body, however <tt>CLASS_REQUIRES</tt> uses C++ language features that
are less portable.
<p>
Next we check that the <tt>iterator_category</tt> of the iterator is
either <tt>std::random_access_iterator_tag</tt> or a derived class.
After that we write out some code that corresponds to the valid
expressions of the <a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a> concept. Typedefs can also be added to
enforce the associated types of the concept.
<pre>
template &lt;class Iter&gt;
struct RandomAccessIterator_concept
{
void constraints() {
function_requires&lt; BidirectionalIteratorConcept&lt;Iter&gt; &gt;();
function_requires&lt; LessThanComparableConcept&lt;Iter&gt; &gt;();
function_requires&lt; ConvertibleConcept&lt;
typename std::iterator_traits&lt;Iter&gt;::iterator_category,
std::random_access_iterator_tag&gt; &gt;();
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&lt;Iter&gt;::difference_type n;
};
}
</pre>
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).
<h2><a name="concept-covering">Concept Covering and Archetypes</a></h2>
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 <i>cover</i> 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 <i>archetype classes</i>. 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 <a
href="http://www.sgi.com/Technology/STL/trivial.html">TrivialIterator</a>
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 <tt>operator*()</tt> must be convertible to the value
type. It does not state the more stringent requirement that the return
type be <tt>T&amp;</tt> or <tt>const T&amp;</tt>. That means it would be a
mistake to use <tt>T&amp;</tt> or <tt>const T&amp;</tt> for the return type
of the archetype class. The correct approach is to create an
artificial return type that is convertible to <tt>T</tt>, as we have
done here with <tt>input_proxy</tt>. 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.
<pre>
template &lt;class T&gt;
struct input_proxy {
operator T() { return t; }
static T t;
};
template &lt;class T&gt;
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&lt;T&gt; operator*() { return input_proxy&lt;T&gt;(); }
};
namespace std {
template &lt;class T&gt;
struct iterator_traits&lt; trivial_iterator_archetype&lt;T&gt; &gt;
{
typedef T value_type;
};
}
</pre>
Generic algorithms are often tested by being instantiated with a
number of common input types. For example, one might apply
<tt>std::stable_sort()</tt> 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.
<p>
The following is an excerpt from <a
href="./stl_concept_covering.cpp"><tt>stl_concept_covering.cpp</tt></a>
that shows how archetypes can be used to check the requirement
documentation for
<a href="http://www.sgi.com/Technology/STL/stable_sort.html">
<tt>std::stable_sort()</tt></a>. In this case, it looks like the <a
href="../utility/CopyConstructible.html">CopyConstructible</a> and <a
href="../utility/Assignable.html">Assignable</a> 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 <tt>Base</tt> indicate where the
layered archetype can be used.
<pre>
{
typedef less_than_comparable_archetype&lt;
copy_constructible_archetype&lt;
assignable_archetype&lt;&gt; &gt; &gt; ValueType;
random_access_iterator_archetype&lt;ValueType&gt; ri;
std::stable_sort(ri, ri);
}
</pre>
<h2><a name="programming-with-concepts">Programming with Concepts</a></h2>
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 <i>requirement minimization principle</i>.
<p>
<b>Requirement Minimization Principle:</b> Minimize the requirements
on the input parameters of a component to increase its reusability.
<p>
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.
<p>
The traditional notions of <i>abstraction</i> 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.
<p>
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.
<p>
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
<tt>std::stable_sort()</tt> function requires that the value type of
the iterator be <a
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a>, which not only
includes <tt>operator&lt;()</tt>, but also <tt>operator&gt;()</tt>,
<tt>operator&lt;=()</tt>, and <tt>operator&gt;=()</tt>.
It turns out that <tt>std::stable_sort()</tt> only uses
<tt>operator&lt;()</tt>. The question then arises: should
<tt>std::stable_sort()</tt> be specified in terms of the concept
<a
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a> or in terms of a concept that only
requires <tt>operator&lt;()</tt>?
<p>
We remark first that the use of <a
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a> does not really violate the requirement
minimization principle because all of the other operators can be
trivially implemented in terms of <tt>operator&lt;()</tt>. By
``trivial'' we mean one line of code and a constant run-time cost.
More fundamentally, however, the use of <a
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a> does not violate the requirement minimization
principle because all of the comparison operators (<tt>&lt;</tt>,
<tt>></tt>, <tt><=</tt>, <tt>>=</tt>) 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.
<p>
For example,
the
maintainer of the <tt>std::stable_sort()</tt> may some day change the
implementation in places to use <tt>operator>()</tt> instead of
<tt>operator<()</tt>, 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
<a
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
LessThanComparable</a> is given as the requirement for
<tt>std::stable_sort()</tt>, then the maintainer is given a reasonable
amount of flexibility within which to work.
<p>
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 <a
href="http://www.sgi.com/Technology/STL/ForwardIterator.html">
ForwardIterator</a> and
<a
href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
BidirectionalIterator</a>). 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).
<h2><a name="implementation">Implementation</a></h2>
Ideally we would like to catch, and indicate, the concept violation at
the point of instantiation. As mentioned in D&amp;E[<a
href="bibliography.html#stroustrup94:_design_evolution">2</a>], 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 --- <i>but not executed</i>. 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 <tt>std::stable_sort()</tt> function:
<pre>
template &lt;class RandomAccessIterator&gt;
void stable_sort_constraints(RandomAccessIterator i) {
typename std::iterator_traits&lt;RandomAccessIterator&gt;
::difference_type n;
i += n; // exercise the requirements for RandomAccessIterator
...
}
template &lt;class RandomAccessIterator&gt;
void stable_sort(RandomAccessIterator first, RandomAccessIterator last) {
typedef void (*fptr_type)(RandomAccessIterator);
fptr_type x = &stable_sort_constraints;
...
}
</pre>
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 <tt>stable_sort_constraints()</tt> 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 <tt>contraints()</tt> member function which exercises all of the
valid expressions of the concept. The objects used in the constraints
function, such as <tt>n</tt> and <tt>i</tt>, are declared as data
members of the concept checking class.
<pre>
template &lt;class Iter&gt;
struct RandomAccessIterator_concept {
void constraints() {
i += n;
...
}
typename std::iterator_traits&lt;RandomAccessIterator&gt;
::difference_type n;
Iter i;
...
};
</pre>
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 <tt>function_requires()</tt>. The following code
snippet shows how to use <tt>function_requires()</tt> to make sure
that the iterator is a
<a
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a>.
<pre>
template &lt;class RandomAccessIter&gt;
void stable_sort(RandomAccessIter first, RandomAccessIter last)
{
function_requires< RandomAccessIteratorConcept<RandomAccessIter> >();
...
}
</pre>
The definition of the <tt>function_requires()</tt> is as follows. The
<tt>Concept</tt> 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 <tt>x</tt>, which
causes the instantiation of the constraints function and checking of
the concept's valid expressions. We then assign <tt>x</tt> to
<tt>x</tt> to avoid unused variable compiler warnings, and wrap
everything in a do-while loop to prevent name collisions.
<pre>
template <class Concept>
void function_requires()
{
void (Concept::*x)() = BOOST_FPTR Concept::constraints;
ignore_unused_variable_warning(x);
}
</pre>
To check the type parameters of class templates, we provide the
<tt>class_requires</tt> class which can be used inside the body of a
class definition (whereas <tt>function_requires()</tt> can only be
used inside of a function body). <tt>class_requires</tt> 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.
<pre>
template &lt;class Concept&gt;
class class_requires
{
typedef void (Concept::* function_pointer)();
template &lt;function_pointer Fptr&gt;
struct dummy_struct { };
public:
typedef dummy_struct&lt; BOOST_FPTR Concept::constraints &gt; check;
};
</pre>
<tt>class_requires</tt> 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.
<h2><a name="reference">Reference</a></h2>
<h3><a name="functions">Functions</a></h3>
<pre>
template &lt;class Concept&gt;
void function_requires();
</pre>
<h3><a name="classes">Classes</a></h3>
<pre>
template &lt;class Concept&gt;
struct class_requires {
typedef ... check;
};
</pre>
<pre>
// Make sure that <i>Type1</i> and <i>Type2</i> are exactly the same type.
// If they are not, then the nested typedef for <tt>type</tt> will
// not exist and cause a compiler error.
template &lt;class Type1, class Type2&gt;
struct require_same {
typedef ... type;
};
// usage example
typedef typedef require_same<int,int>::type req1; // this will compile OK
typedef typedef require_same<int,float>::type req1; // this will cause a compiler error
</pre>
<h3><a name="basic-concepts">Basic Concept Checking Classes</a></h3>
<pre>
template &lt;class T&gt; struct Integer_concept; // Is T a built-in integer type?
template &lt;class T&gt; struct SignedIntegerConcept; // Is T a built-in signed integer type?
template &lt;class X, class Y&gt; struct ConvertibleConcept; // Is X convertible to Y?
template &lt;class T&gt; struct AssignableConcept;
template &lt;class T&gt; struct DefaultConstructibleConcept;
template &lt;class T&gt; struct CopyConstructibleConcept;
template &lt;class T&gt; struct BooleanConcept;
template &lt;class T&gt; struct EqualityComparableConcept;
// Is class T equality comparable on the left side with type Left?
template &lt;class T, class Left&gt; struct LeftEqualityComparableConcept;
template &lt;class T&gt; struct LessThanComparableConcept;
</pre>
<h3><a name="iterator-concepts">Iterator Concept Checking Classes</a></h3>
<pre>
template &lt;class Iter&gt; struct TrivialIteratorConcept;
template &lt;class Iter&gt; struct Mutable_TrivialIteratorConcept;
template &lt;class Iter&gt; struct InputIteratorConcept;
template &lt;class Iter, class T&gt; struct OutputIteratorConcept;
template &lt;class Iter&gt; struct ForwardIteratorConcept;
template &lt;class Iter&gt; struct Mutable_ForwardIteratorConcept;
template &lt;class Iter&gt; struct BidirectionalIteratorConcept;
template &lt;class Iter&gt; struct Mutable_BidirectionalIteratorConcept;
template &lt;class Iter&gt; struct RandomAccessIteratorConcept;
template &lt;class Iter&gt; struct Mutable_RandomAccessIteratorConcept;
</pre>
<h3><a name="function-object-concepts">Function Object Concept Checking Classes</a></h3>
<pre>
template &lt;class Func, class Return&gt; struct GeneratorConcept;
template &lt;class Func, class Return, class Arg&gt; struct UnaryFunctionConcept;
template &lt;class Func, class Return, class First, class Second&gt; struct BinaryFunctionConcept;
template &lt;class Func, class Arg&gt; struct UnaryPredicateConcept;
template &lt;class Func, class First, class Second&gt; struct BinaryPredicateConcept;
template &lt;class Func, class First, class Second&gt; struct Const_BinaryPredicateConcept {;
</pre>
<h3><a name="container-concepts">Container Concept Checking Classes</a></h3>
<pre>
template &lt;class C&gt; struct ContainerConcept;
template &lt;class C&gt; struct Mutable_ContainerConcept;
template &lt;class C&gt; struct ForwardContainerConcept;
template &lt;class C&gt; struct Mutable_ForwardContainerConcept;
template &lt;class C&gt; struct ReversibleContainerConcept;
template &lt;class C&gt; struct Mutable_ReversibleContainerConcept;
template &lt;class C&gt; struct RandomAccessContainerConcept;
template &lt;class C&gt; struct Mutable_RandomAccessContainerConcept;
template &lt;class C&gt; struct SequenceConcept;
template &lt;class C&gt; struct FrontInsertionSequenceConcept;
template &lt;class C&gt; struct BackInsertionSequenceConcept;
template &lt;class C&gt; struct AssociativeContainerConcept;
template &lt;class C&gt; struct UniqueAssociativeContainerConcept;
template &lt;class C&gt; struct MultipleAssociativeContainerConcept;
template &lt;class C&gt; struct SimpleAssociativeContainerConcept;
template &lt;class C&gt; struct PairAssociativeContainerConcept;
template &lt;class C&gt; struct SortedAssociativeContainerConcept;
</pre>
<h3><a name="basic-archetype">Basic Archetype Classes</a></h3>
<pre>
class null_archetype; // A type that models no concepts.
template &lt;class Base = null_archetype&gt; class default_constructible_archetype;
template &lt;class Base = null_archetype&gt; class assignable_archetype;
template &lt;class Base = null_archetype&gt; class copy_constructible_archetype;
template &lt;class Left, class Base = null_archetype&gt; class left_equality_comparable_archetype;
template &lt;class Base = null_archetype&gt; class equality_comparable_archetype;
template &lt;class T, class Base = null_archetype&gt; class convertible_to_archetype;
</pre>
<h3><a name="iterator-archetype">Iterator Archetype Classes</a></h3>
<pre>
template &lt;class ValueType&gt; class trivial_iterator_archetype;
template &lt;class ValueType&gt; class mutable_trivial_iterator_archetype;
template &lt;class ValueType&gt; class input_iterator_archetype;
template &lt;class ValueType&gt; class forward_iterator_archetype;
template &lt;class ValueType&gt; class bidirectional_iterator_archetype;
template &lt;class ValueType&gt; class random_access_iterator_archetype;
</pre>
<h3><a name="function-object-archetype">Function Object Archetype Classes</a></h3>
<pre>
template &lt;class Arg, class Return&gt; class unary_function_archetype;
template &lt;class Arg1, class Arg2, class Return&gt; class binary_function_archetype;
template &lt;class Arg&gt; class predicate_archetype;
template &lt;class Arg1, class Arg2&gt; class binary_predicate_archetype;
</pre>
<h3><a name="container-archetype">Container Archetype Classes</a></h3>
<pre>
UNDER CONSTRUCTION
</pre>
<h2><a name="history">History</a></h2>
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.
<h2><a name="publications">Publications</a></h2>
<ul>
<li><a href="http://www.oonumerics.org/tmpw00/">
C++ Template Workshop 2000</a>, Concept Checking</li>
</ul>
<h2><a name="acknowledgements">Acknowledgements</a></h2>
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&amp;E[
<a href="bibliography.html#stroustrup94:_design_evolution">2</a>].
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.
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>,
Univ.of Notre Dame (<A
HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

View File

@ -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 <boost/pending/concept_checks.hpp>
/*
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<foo> >();
return 0;
}

View File

@ -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 <boost/pending/concept_checks.hpp>
#include <boost/pending/concept_archetypes.hpp>
/*
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<foo> >();
}
{
typedef assignable_archetype<> foo;
function_requires< AssignableConcept<foo> >();
}
{
typedef copy_constructible_archetype<> foo;
function_requires< CopyConstructibleConcept<foo> >();
}
{
typedef sgi_assignable_archetype<> foo;
function_requires< SGIAssignableConcept<foo> >();
}
{
typedef copy_constructible_archetype<> foo;
typedef convertible_to_archetype<foo> convertible_to_foo;
function_requires< ConvertibleConcept<convertible_to_foo, foo> >();
}
{
function_requires< ConvertibleConcept<boolean_archetype, bool> >();
}
{
typedef equality_comparable_archetype<> foo;
function_requires< EqualityComparableConcept<foo> >();
}
{
typedef less_than_comparable_archetype<> foo;
function_requires< LessThanComparableConcept<foo> >();
}
{
typedef comparable_archetype<> foo;
function_requires< ComparableConcept<foo> >();
}
{
typedef equal_op_first_archetype<> First;
typedef equal_op_second_archetype<> Second;
function_requires< EqualOpConcept<First, Second> >();
}
{
typedef not_equal_op_first_archetype<> First;
typedef not_equal_op_second_archetype<> Second;
function_requires< NotEqualOpConcept<First, Second> >();
}
{
typedef less_than_op_first_archetype<> First;
typedef less_than_op_second_archetype<> Second;
function_requires< LessThanOpConcept<First, Second> >();
}
{
typedef less_equal_op_first_archetype<> First;
typedef less_equal_op_second_archetype<> Second;
function_requires< LessEqualOpConcept<First, Second> >();
}
{
typedef greater_than_op_first_archetype<> First;
typedef greater_than_op_second_archetype<> Second;
function_requires< GreaterThanOpConcept<First, Second> >();
}
{
typedef greater_equal_op_first_archetype<> First;
typedef greater_equal_op_second_archetype<> Second;
function_requires< GreaterEqualOpConcept<First, Second> >();
}
{
typedef copy_constructible_archetype<> Return;
typedef plus_op_first_archetype<Return> First;
typedef plus_op_second_archetype<Return> Second;
function_requires< PlusOpConcept<Return, First, Second> >();
}
//===========================================================================
// Function Object Concepts
{
typedef generator_archetype<null_archetype<> > foo;
function_requires< GeneratorConcept<foo, null_archetype<> > >();
}
{
function_requires< GeneratorConcept< void_generator_archetype, void > >();
}
{
typedef unary_function_archetype<int, int> F;
function_requires< UnaryFunctionConcept<F, int, int> >();
}
{
typedef binary_function_archetype<int, int, int> F;
function_requires< BinaryFunctionConcept<F, int, int, int> >();
}
{
typedef unary_predicate_archetype<int> F;
function_requires< UnaryPredicateConcept<F, int> >();
}
{
typedef binary_predicate_archetype<int, int> F;
function_requires< BinaryPredicateConcept<F, int, int> >();
typedef const_binary_predicate_archetype<int, int> const_F;
function_requires< Const_BinaryPredicateConcept<const_F, int, int> >();
}
//===========================================================================
// Iterator Concepts
{
typedef trivial_iterator_archetype<null_archetype<> > Iter;
function_requires< TrivialIteratorConcept<Iter> >();
}
{
typedef mutable_trivial_iterator_archetype<null_archetype<> > Iter;
function_requires< Mutable_TrivialIteratorConcept<Iter> >();
}
{
typedef input_iterator_archetype<null_archetype<> > Iter;
function_requires< InputIteratorConcept<Iter> >();
}
{
typedef output_iterator_archetype Iter;
function_requires< OutputIteratorConcept<Iter, int> >();
}
{
typedef forward_iterator_archetype<null_archetype<> > Iter;
function_requires< ForwardIteratorConcept<Iter> >();
}
{
typedef forward_iterator_archetype<assignable_archetype<> > Iter;
function_requires< Mutable_ForwardIteratorConcept<Iter> >();
}
{
typedef bidirectional_iterator_archetype<null_archetype<> > Iter;
function_requires< BidirectionalIteratorConcept<Iter> >();
}
{
typedef bidirectional_iterator_archetype<assignable_archetype<> > Iter;
function_requires< Mutable_BidirectionalIteratorConcept<Iter> >();
}
{
typedef random_access_iterator_archetype<null_archetype<> > Iter;
function_requires< RandomAccessIteratorConcept<Iter> >();
}
{
typedef random_access_iterator_archetype<assignable_archetype<> > Iter;
function_requires< Mutable_RandomAccessIteratorConcept<Iter> >();
}
//===========================================================================
// Container Concepts
{
function_requires< ContainerConcept< > >();
}
{
}
return 0;
}

View File

@ -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 <boost/pending/concept_checks.hpp>
#include <iterator>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <deque>
#ifndef BOOST_NO_SLIST
#include <slist>
#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<int> Vector;
typedef std::deque<int> Deque;
typedef std::list<int> List;
// VC++ missing pointer and const_pointer typedefs
function_requires< Mutable_RandomAccessContainerConcept<Vector> >();
function_requires< BackInsertionSequenceConcept<Vector> >();
#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<Deque> >();
#endif
// warnings about signed and unsigned in old deque version
function_requires< FrontInsertionSequenceConcept<Deque> >();
function_requires< BackInsertionSequenceConcept<Deque> >();
#endif
// VC++ missing pointer and const_pointer typedefs
function_requires< Mutable_ReversibleContainerConcept<List> >();
function_requires< FrontInsertionSequenceConcept<List> >();
function_requires< BackInsertionSequenceConcept<List> >();
#ifndef BOOST_NO_SLIST
typedef std::slist<int> SList;
function_requires< FrontInsertionSequenceConcept<SList> >();
#endif
typedef std::set<int> Set;
typedef std::multiset<int> MultiSet;
typedef std::map<int,int> Map;
typedef std::multimap<int,int> MultiMap;
function_requires< SortedAssociativeContainerConcept<Set> >();
function_requires< SimpleAssociativeContainerConcept<Set> >();
function_requires< UniqueAssociativeContainerConcept<Set> >();
function_requires< SortedAssociativeContainerConcept<MultiSet> >();
function_requires< SimpleAssociativeContainerConcept<MultiSet> >();
function_requires< MultipleAssociativeContainerConcept<MultiSet> >();
function_requires< SortedAssociativeContainerConcept<Map> >();
function_requires< UniqueAssociativeContainerConcept<Map> >();
function_requires< PairAssociativeContainerConcept<Map> >();
function_requires< SortedAssociativeContainerConcept<MultiMap> >();
function_requires< MultipleAssociativeContainerConcept<MultiMap> >();
function_requires< PairAssociativeContainerConcept<MultiMap> >();
#endif
return 0;
}