Updated Concept Check library documentation.

Changed BOOST_CONCEPT_WHERE to BOOST_CONCEPT_REQUIRES to be more
consistent with the current C++0x proposal, which now uses a
"requires" keyword in lieu of "where."

Factored GCC workarounds into the BOOST_CONCEPT_USAGE macro.


[SVN r40769]
This commit is contained in:
Dave Abrahams
2007-11-05 03:54:19 +00:00
parent 6ed3c013bb
commit 7dd50ca8f2
12 changed files with 1293 additions and 1336 deletions

View File

@ -1,13 +1,14 @@
#include <vector>
#include <complex>
#include "algorithm"
int main()
{
std::vector<std::complex<float> > v;
std_::stable_sort(v.begin(), v.end());
}
// (C) Copyright Jeremy Siek 2000. // (C) Copyright Jeremy Siek 2000.
// Distributed under the Boost Software License, Version 1.0. (See // Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at // accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#include <list>
#include <algorithm>
int main() {
std::list<int> v;
std::stable_sort(v.begin(), v.end());
return 0;
}

View File

@ -1,312 +1,330 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000
-- <html xmlns="http://www.w3.org/1999/xhtml">
-- Permission to use, copy, modify, distribute and sell this software <!-- Copyright (c) 2000 Jeremy Siek and Andrew Lumsdaine, 2007 David Abrahams -->
-- and its documentation for any purpose is hereby granted without fee, <!-- Distributed under the Boost -->
-- provided that the above copyright notice appears in all copies and <!-- Software License, Version 1.0. (See accompanying -->
-- that both that copyright notice and this permission notice appear <!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
-- in supporting documentation. We make no
-- representations about the suitability of this software for any <head>
-- purpose. It is provided "as is" without express or implied warranty. <meta name="generator" content=
--> "HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
<Head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<Title>Concept Check Library</Title>
<title>Concept Check Library</title>
<link rel="stylesheet" href="../../rst.css" type="text/css" />
</head> </head>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b" <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
ALINK="#ff0000"> "#FF0000">
<IMG SRC="../../boost.png" <img src="../../boost.png" alt="C++ Boost" width="277" height=
ALT="C++ Boost" width="277" height="86"> "86" /><br clear="none" />
<BR Clear> <h1>The Boost Concept Check Library (BCCL)</h1>
<H1>The Boost Concept Check Library (BCCL)</H1> <blockquote>
The Concept Check library allows one to add explicit statement and
checking of <a href=
"../../more/generic_programming.html#concept">concepts</a> in the style
of the <a href=
"http://www.generic-programming.org/languages/conceptcpp/specification/">proposed
C++ language extension</a>.
</blockquote>
<h2> <h2><a name="sec:concept-checking" id="sec:concept-checking"></a>Synopsis</a></h2>
<A NAME="sec:concept-checking"></A>
header <a href="../../boost/concept_check.hpp">
<tt>boost/concept_check.hpp</tt></a>
<br>and <a href="../../boost/concept_archetype.hpp">
<tt>boost/concept_archetype.hpp</tt></a>
</h2>
<p> <p>Generic programming in C++ is characterized by the use of template
Generic programming in C++ is characterized by the use of template parameters to represent abstract data types (or “<a href=
parameters to represent abstract data types (or ``concepts''). "../../more/generic_programming.html#concept">concepts</a>”). However, the
However, the C++ language itself does not provide a mechanism for the C++ language itself does not provide a mechanism for the writer of a class
writer of a class or function template to explicitly state what or function template to explicitly state the concept that the user-supplied
concept the user-supplied template argument should model (or conform template argument should model (or conform to). Template parameters are
to). The common practice is to name the template parameter after the commonly named after the concept they're required to model as a hint to the
required concept as a hint to the user and to state the concept user, and to make the concept requirements explicit in code. However, the
requirements in the documentation. However, often times the compiler doesn't treat these special names specially: a parameter named
requirements are vague, incorrect, or nonexistent, which is quite a <code>RandomAccessIterator</code> is no different to the compiler than one
problem for the user, since he or she will not know exactly what kind named <code>T</code>. Furthermore,</p>
of input is expected by the template. Furthermore, the following
problems occur:
<ul> <ul>
<li>Compiler error messages resulting from incorrect template <li>Compiler error messages resulting from incorrect template arguments
arguments can be particularly difficult to decipher. Often times can be particularly difficult to decipher. Often times the error does not
the error does not point to the location of the template point to the location of the template call-site, but instead exposes the
call-site, but instead exposes the internals of the template, which internals of the template, which the user should never have to see.</li>
the user should never have to see.</li>
<li>The documented concept requirements may not fully <i>cover</i> <li>Without checking from the compiler, the documented requirements are
the template, meaning the user could get a compiler error even oftentimes vague, incorrect, or nonexistent, so a user cannot know
though the supplied template arguments meet the documented exactly what kind of arguments are expected.</li>
requirements.</li>
<li>The documented concept requirements may be too stringent, <li>The documented concept requirements may not fully <i>cover</i> the
requiring more than is really needed by the template.</li> needs of the actual template, meaning the user could get a compiler error
even though the supplied template arguments meet the documented
requirements.</li>
<li>The requirements are not explicitly stated in the code, which <li>The documented concept requirements may be too stringent, requiring
makes the code harder to understand. Also, the code may more than is really needed by the template.</li>
get out-of-sync with the documented requirements.</li>
</ul>
The Boost Concept Checking Library provides: <li>Concept names in code may drift out-of-sync with the documented
requirements.</li>
</ul><p>The Boost Concept Checking Library provides:
<ul> <ul>
<li>A mechanism for inserting compile-time checks of template <li>A mechanism for inserting compile-time checks on template parameters
parameters.</li> at their point of use.</li>
<li>A framework for specifying concept requirements though concept <li>A framework for specifying concept requirements though concept
checking classes.</li> checking classes.</li>
<li>A mechanism for verifying that concept requirements cover the template.</li> <li>A mechanism for verifying that concept requirements cover the
template.</li>
<li>A suite of concept checking classes and archetype classes that <li>A suite of concept checking classes and archetype classes that match
match the concept requirements in the C++ Standard Library.</li> the concept requirements in the C++ Standard Library.</li>
</ul>
The mechanisms use standard C++ and introduce no run-time <li>An alternative to the use of traits classes for accessing associated
overhead. The main cost of using the mechanism is in compile-time. types that mirrors the syntax proposed for the next C++ standard.</li>
</ul><p>The mechanisms use standard C++ and introduce no run-time overhead.
The main cost of using the mechanism is in compile-time.</p>
<p> <p><strong>Every programmer writing class or function templates ought to
Any programmer writing class or function templates ought to make make concept checking a normal part of their code writing routine.</strong>
concept checking a normal part of their code writing routine. A A concept check should be inserted for each template parameter in a
concept check should be inserted for each template parameter in a component's public interface. If the concept is one of the ones from the
component's public interface. If the concept is one of the ones from Standard Library, then simply use the matching concept checking class in
the Standard Library, then simply use the matching concept checking the BCCL. If not, then write a new concept checking class - after all, they
class in the BCCL. If not, then write a new concept checking class - are typically only a few lines long. For new concepts, a matching archetype
after all, they are typically only a few lines long. For new concepts, class should also be created, which is a minimal skeleton-implementation of
a matching archetype class should also be created, which is a minimal the concept</p>
skeleton-implementation of the concept
<p> <p>The documentation is organized into the following sections.</p>
The documentation is organized into the following sections.
<OL> <ol>
<LI><a href="#introduction">Introduction</a></LI> <li><a href="#introduction">Introduction</a></li>
<LI><a href="#motivating-example">Motivating Example</a></LI>
<LI><a href="#history">History</a></LI>
<LI><a href="#publications">Publications</a></LI>
<LI><a href="#acknowledgements">Acknowledgements</a></LI>
<LI><a href="./using_concept_check.htm">Using Concept Checks</a></LI>
<LI><a href="creating_concepts.htm">Creating Concept Checking Classes</a></LI>
<LI><a href="./concept_covering.htm">Concept Covering and Archetypes</a></LI>
<LI><a href="./prog_with_concepts.htm" ">Programming With Concepts</a></LI>
<LI><a href="./implementation.htm">Implementation</a></LI>
<LI><a href="./reference.htm">Reference</a></LI>
</OL>
<p> <li><a href="#motivating-example">Motivating Example</a></li>
<a href="../../people/jeremy_siek.htm">Jeremy Siek</a> contributed
this library. <a href="../../people/beman_dawes.html">Beman Dawes</a>
managed the formal review.
<h2><a name="introduction">Introduction</a></h2> <li><a href="#history">History</a></li>
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> <li><a href="#publications">Publications</a></li>
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> <li><a href="#acknowledgements">Acknowledgements</a></li>
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> <li><a href="./using_concept_check.htm">Using Concept Checks</a></li>
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> <li><a href="creating_concepts.htm">Creating Concept Checking
Classes</a></li>
We present a simple example to illustrate incorrect usage of a <li><a href="./concept_covering.htm">Concept Covering and
template library and the resulting error messages. In the code below, Archetypes</a></li>
the generic <tt>std::stable_sort()</tt> algorithm from the Standard
Template Library (STL)[<a
href="bibliography.htm#austern99:_gener_progr_stl">3</a>, <a
href="bibliography.htm#IB-H965502">4</a>,<a
href="bibliography.htm#stepa.lee-1994:the.s:TR">5</a>] is applied to
a linked list.
<pre> <li><a href="./prog_with_concepts.htm">Programming With Concepts</a></li>
<li><a href="./implementation.htm">Implementation</a></li>
<li><a href="./reference.htm">Reference</a></li>
</ol>
<p><a href="../../people/jeremy_siek.htm">Jeremy Siek</a> contributed this
library. <a href="../../people/beman_dawes.html">Beman Dawes</a> managed
the formal review. <a href="../../people/dave_abrahams.htm">Dave
Abrahams</a> contributed a rewrite that updated syntax to be more
compatible with proposed syntax for concept support the C++ core
language.</p>
<h2><a name="introduction" id="introduction">Introduction</a></h2><p>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>
<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>
<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..</p>
<h2><a name="motivating-example" id="motivating-example">Motivating
Example</a></h2>
<p>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.htm#austern99:_gener_progr_stl">3</a>, <a href=
"bibliography.htm#IB-H965502">4</a>,<a href=
"bibliography.htm#stepa.lee-1994:the.s:TR">5</a>] is applied to a linked
list.</p>
<pre>
<a href="./bad_error_eg.cpp">bad_error_eg.cpp</a>: <a href="./bad_error_eg.cpp">bad_error_eg.cpp</a>:
1 #include &lt;list&gt; <font color="gray">1</font> #include &lt;vector&gt;
2 #include &lt;algorithm&gt; <font color="gray">2</font color="gray"> #include &lt;complex&gt;
3 <font color="gray">3</font color="gray"> #include &lt;algorithm&gt;
4 int main(int, char*[]) { <font color="gray">4</font color="gray">
5 std::list&lt;int&gt; v; <font color="gray">5</font color="gray"> int main()
6 std::stable_sort(v.begin(), v.end()); <font color="gray">6</font color="gray"> {
7 return 0; <font color="gray">7</font color="gray"> std::vector&lt;std::complex&lt;float&gt; &gt; v;
8 } <font color="gray">8</font color="gray"> std::stable_sort(v.begin(), v.end());
<font color="gray">9</font color="gray"> }
</pre> </pre>
Here, the <p>Here, the <tt>std::stable_sort()</tt> algorithm is prototyped as
<tt>std::stable_sort()</tt> algorithm is prototyped as follows: follows:</p>
<pre> <pre>
template &lt;class RandomAccessIterator&gt; template &lt;class RandomAccessIterator&gt;
void stable_sort(RandomAccessIterator first, RandomAccessIterator last); void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
</pre> </pre>
Attempting to compile this code with Gnu C++ produces the following <p>Attempting to compile this code with Gnu C++ produces the following
compiler error. The output from other compilers is listed in the compiler error:</p>
Appendix. <pre>
/usr/include/c++/4.1.2/bits/stl_algo.h: In function void std::
<pre> __insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with
stl_algo.h: In function `void __merge_sort_loop&lt;_List_iterator _RandomAccessIterator = __gnu_cxx::__normal_iterator&lt;std::complex&lt;float
&lt;int,int &amp;,int *&gt;, int *, int&gt;(_List_iterator&lt;int,int &amp;,int *&gt;, &gt;*, std::vector&lt;std::complex&lt;float&gt;, std::allocator&lt;std::complex&lt;
_List_iterator&lt;int,int &amp;,int *&gt;, int *, int)': float&gt; &gt; &gt; &gt;]:
stl_algo.h:1448: instantiated from `__merge_sort_with_buffer /usr/include/c++/4.1.2/bits/stl_algo.h:3066: instantiated from void
&lt;_List_iterator&lt;int,int &amp;,int *&gt;, int *, int&gt;( std::__inplace_stable_sort(_RandomAccessIterator,
_List_iterator&lt;int,int &amp;,int *&gt;, _List_iterator&lt;int,int &amp;,int *&gt;, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::
int *, int *)' __normal_iterator&lt;std::complex&lt;float&gt;*, std::vector&lt;std::complex&lt;
stl_algo.h:1485: instantiated from `__stable_sort_adaptive&lt; float&gt;, std::allocator&lt;std::complex&lt;float&gt; &gt; &gt; &gt;]
_List_iterator&lt;int,int &amp;,int *&gt;, int *, int&gt;(_List_iterator /usr/include/c++/4.1.2/bits/stl_algo.h:3776: instantiated from void
&lt;int,int &amp;,int *&gt;, _List_iterator&lt;int,int &amp;,int *&gt;, int *, int)' std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with
stl_algo.h:1524: instantiated from here _RandomAccessIterator = __gnu_cxx::__normal_iterator&lt;std::complex&lt;float
stl_algo.h:1377: no match for `_List_iterator&lt;int,int &amp;,int *&gt; &amp; - &gt;*, std::vector&lt;std::complex&lt;float&gt;, std::allocator&lt;std::complex&lt;
_List_iterator&lt;int,int &amp;,int *&gt; &amp;' float&gt; &gt; &gt; &gt;]
bad_error_eg.cpp:8: instantiated from here
/usr/include/c++/4.1.2/bits/stl_algo.h:2277: error: no match for
operator&lt; in __val &lt; __first. __gnu_cxx::__normal_iterator&lt;
_Iterator, _Container&gt;::operator* [with _Iterator = std::complex&lt;float
&gt;*, _Container = std::vector&lt;std::complex&lt;float&gt;, std::allocator&lt;
std::complex&lt;float&gt; &gt; &gt;]()
</pre> </pre>
In this case, the fundamental error is that <p>In this case, the fundamental error is
<tt>std:list::iterator</tt> does not model the concept of <a that <tt>std:complex&lt;float&gt;</tt> does not model the <a href=
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> "http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</a>
RandomAccessIterator</a>. The list iterator is only bidirectional, not concept. Unfortunately, there is nothing in the error message to
fully random access (as would be a vector iterator). Unfortunately, indicate that to the user.</p>
there is nothing in the error message to indicate this to the user.
<p> <p>The error may be obvious to a C++ programmer having enough
To a C++ programmer having enough experience with template libraries experience with template libraries, but there are several reasons
the error may be obvious. However, for the uninitiated, there are several why this message could be hard for the uninitiated to
reasons why this message would be hard to understand. understand:</p>
<OL> <ol>
<LI> The location of the error, line 6 of <tt>bad_error_eg.cpp</tt> <li>There is no textual correlation between the error message and the
is not pointed to by the error message, despite the fact that Gnu C++ documented requirements for <tt>std::stable_sort()</tt> and for <a href=
prints up to 4 levels deep in the instantiation stack. "http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</a>.</li>
<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/tech/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 <li>The error message is overly long, listing functions internal
informative message (and is in fact what the Boost Concept Checking to the STL (e.g. <code>__insertion_sort</code>) that the user
Library produces): does not (and should not!) know or care about.</li>
<pre> <li>With so many internal library functions listed in the error message,
boost/concept_check.hpp: In method `void LessThanComparableConcept the programmer could easily infer that the problem is in the library,
&lt;_List_iterator&lt;int,int &amp;,int *&gt; &gt;::~LessThanComparableConcept()': rather than in his or her own code.</li>
boost/concept_check.hpp:334: instantiated from `RandomAccessIteratorConcept </ol>
&lt;_List_iterator&lt;int,int &amp;,int *&gt; &gt;::~RandomAccessIteratorConcept()'
bad_error_eg.cpp:6: instantiated from `stable_sort&lt;_List_iterator <p>The following is an example of what we might expect from a more
&lt;int,int &amp;,int *&gt; &gt;(_List_iterator&lt;int,int &amp;,int *&gt;, informative message (and is in fact what the Boost Concept Checking Library
_List_iterator&lt;int,int &amp;,int *&gt;)' produces):</p>
boost/concept_check.hpp:209: no match for `_List_iterator&lt;int,int &amp;,int *&gt; &amp; <pre>
&lt; _List_iterator&lt;int,int &amp;,int *&gt; &amp;' boost/concept_check.hpp: In destructor boost::LessThanComparable&lt;TT&gt;::~
LessThanComparable() [with TT = std::complex&lt;float&gt;]:
boost/concept/detail/general.hpp:29: instantiated from static void boost::
concept::requirement&lt;Model&gt;::failed() [with Model = boost::
LessThanComparable&lt;std::complex&lt;float&gt; &gt;]
boost/concept/requires.hpp:30: instantiated from boost::_requires_&lt;void
(*)(boost::LessThanComparable&lt;std::complex&lt;float&gt; &gt;)&gt;
bad_error_eg.cpp:8: instantiated from here
boost/concept_check.hpp:236: error: no match for operator&lt; in ((boost::
LessThanComparable&lt;std::complex&lt;float&gt; &gt;*)this)-&gt;boost::
LessThanComparable&lt;std::complex&lt;float&gt; &gt;::a &lt; ((boost::
LessThanComparable&lt;std::complex&lt;float&gt; &gt;*)this)-&gt;boost::
LessThanComparable&lt;std::complex&lt;float&gt; &gt;::b
</pre> </pre>
This message rectifies several of the shortcomings of the standard <p>This message rectifies several of the shortcomings of the standard error
error messages. messages.</p>
<UL> <ul>
<LI> The location of the error, <tt>bad_error_eg.cpp:6</tt> is <li>The message refers explicitly to concepts that the user can look up
specified in the error message. in the STL documentation (<a href=
<LI> The message refers explicitly to concepts that the user can look "http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</a>).</li>
up in the STL documentation (<a
href="http://www.sgi.com/tech/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_check.hpp</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="history">History</a></h2> <li>The error message is now much shorter and does not reveal
internal STL functions, nor indeed does it even point
to <code>std::stable_sort</code>.</li>
An earlier version of this concept checking system was developed by <li>The presence of <tt>concept_check.hpp</tt> in the error message
the author while working at SGI in their C++ compiler and library alerts the user to the fact that the error lies in the user code and not
group. The earlier version is now part of the SGI STL distribution. The in the library implementation.</li>
boost concept checking library differs from the concept checking in </ul>
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> <h2><a name="history" id="history">History</a></h2>
<ul> <p>The first version of this concept checking system was developed
<li><a href="http://www.oonumerics.org/tmpw00/"> by Jeremy Siek while working at SGI in their C++ compiler and
C++ Template Workshop 2000</a>, Concept Checking</li> library group. That version is now part of the SGI STL
</ul> distribution. The system originally introduced as the boost concept
checking library differs from concept checking in the SGI STL in
that the definition of concept checking classes was greatly
simplified, at the price of less helpful verbiage in the error
messages. In 2006 the system was rewritten (preserving backward
compatibility) by Dave Abrahams to be easier to use, more similar to
the proposed concept support the C++ core language, and to give
better error messages.
</p>
<h2><a name="acknowledgements">Acknowledgements</a></h2> <h2><a name="publications" id="publications">Publications</a></h2>
The idea to use function pointers to cause instantiation is due to <ul>
Alexander Stepanov. I am not sure of the origin of the idea to use <li><a href="http://www.oonumerics.org/tmpw00/">C++ Template Workshop
expressions to do up-front checking of templates, but it did appear in 2000</a>, Concept Checking</li>
D&amp;E[ </ul>
<a href="bibliography.htm#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.
<h2><a name="acknowledgements" id=
"acknowledgements">Acknowledgements</a></h2><p>The idea to use function
pointers to cause instantiation is due to Alexander Stepanov. We are not sure
of the origin of the idea to use expressions to do up-front checking of
templates, but it did appear in D&amp;E[ <a href=
"bibliography.htm#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.
<p> <p><a href="./using_concept_check.htm">Next: Using Concept
<a href="./using_concept_check.htm">Next: Using Concept Checks</a> Checks</a><br /></p>
<hr />
<br> <table>
<HR> <tr valign="top">
<TABLE> <td nowrap="nowrap">Copyright &copy; 2000</td>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY> <td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
</HTML> "mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>),
2007 <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.
</td>
</tr>
</table>
</body>
</html>

View File

@ -1,126 +1,125 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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 Covering and Archetypes</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<h2><a name="concept-covering">Concept Covering and Archetypes</a></h2> <head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
We have discussed how it is important to select the minimal <title>Concept Covering and Archetypes</title>
requirements (concepts) for the inputs to a component, but it is <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
equally important to verify that the chosen concepts <i>cover</i> the <link rel="stylesheet" href="../../rst.css" type="text/css" />
algorithm. That is, any possible user error should be caught by the </head>
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 <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
href="http://www.sgi.com/tech/stl/InputIterator.html">Input "#FF0000">
Iterator</a> concept. Some care must be taken to ensure that the <img src="../../boost.png" alt="C++ Boost" width="277" height=
archetype is an exact match to the concept. For example, the concept "86" /><br clear="none" />
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>reference</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> <h2><a name="concept-covering" id="concept-covering">Concept Covering and
template &lt;class T&gt; Archetypes</a></h2>
class input_iterator_archetype
{ <p>We have discussed how it is important to select the minimal requirements
private: (concepts) for the inputs to a component, but it is equally important to
typedef input_iterator_archetype self; verify that the chosen concepts <i>cover</i> the algorithm. That is, any
public: possible user error should be caught by the concept checks and not let slip
typedef std::input_iterator_tag iterator_category; through. Concept coverage can be verified through the use of <i>archetype
typedef T value_type; classes</i>. An archetype class is an exact implementation of the interface
struct reference { associated with a particular concept. The run-time behavior of the
operator const value_type&amp;() const { return static_object&lt;T&gt;::get(); } 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
typedef const T* pointer; to the component. If the program compiles then one can be sure that the
typedef std::ptrdiff_t difference_type; concepts cover the component. The following code shows the archetype class
self&amp; operator=(const self&amp;) { return *this; } for the <a href="http://www.sgi.com/tech/stl/InputIterator.html">Input
bool operator==(const self&amp;) const { return true; } Iterator</a> concept. Some care must be taken to ensure that the archetype
bool operator!=(const self&amp;) const { return true; } is an exact match to the concept. For example, the concept states that the
reference operator*() const { return reference(); } return type of <tt>operator*()</tt> must be convertible to the value type.
self&amp; operator++() { return *this; } It does not state the more stringent requirement that the return type be
self operator++(int) { return *this; } <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>reference</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.</p>
<pre>
template &lt;class T&gt;
class input_iterator_archetype
{
private:
typedef input_iterator_archetype self;
public:
typedef std::input_iterator_tag iterator_category;
typedef T value_type;
struct reference {
operator const value_type&amp;() const { return static_object&lt;T&gt;::get(); }
}; };
typedef const T* pointer;
typedef std::ptrdiff_t difference_type;
self&amp; operator=(const self&amp;) { return *this; }
bool operator==(const self&amp;) const { return true; }
bool operator!=(const self&amp;) const { return true; }
reference operator*() const { return reference(); }
self&amp; operator++() { return *this; }
self operator++(int) { return *this; }
};
</pre> </pre>
Generic algorithms are often tested by being instantiated with a <p>Generic algorithms are often tested by being instantiated with a number
number of common input types. For example, one might apply of common input types. For example, one might apply
<tt>std::stable_sort()</tt> with basic pointer types as the iterators. <tt>std::stable_sort()</tt> with basic pointer types as the iterators.
Though appropriate for testing the run-time behavior of the algorithm, Though appropriate for testing the run-time behavior of the algorithm, this
this is not helpful for ensuring concept coverage because C++ types is not helpful for ensuring concept coverage because C++ types never match
never match particular concepts, they often provide much more than the particular concepts exactly. Instead, they often provide more than the
minimal functionality required by any one concept. That is, even minimal functionality required by any one concept. Even though the function
though the function template compiles with a given type, the concept template has concept checks, and compiles with a given type, the checks may
requirements may still fall short of covering the functions actual still fall short of covering all the functionality that is actually used.
requirements. This is why it is important to compile with archetype This is why it is important to compile with archetype classes in addition
classes in addition to testing with common input types. to testing with common input types.</p>
<p> <p>The following is an excerpt from <a href=
The following is an excerpt from <a "./stl_concept_covering.cpp"><tt>stl_concept_covering.cpp</tt></a> that
href="./stl_concept_covering.cpp"><tt>stl_concept_covering.cpp</tt></a> shows how archetypes can be used to check the requirement documentation for
that shows how archetypes can be used to check the requirement <a href=
documentation for "http://www.sgi.com/tech/stl/stable_sort.html"><tt>std::stable_sort()</tt></a>.
<a href="http://www.sgi.com/tech/stl/stable_sort.html"> In this case, it looks like the <a href=
<tt>std::stable_sort()</tt></a>. In this case, it looks like the <a "../utility/CopyConstructible.html">CopyConstructible</a> and <a href=
href="../utility/CopyConstructible.html">CopyConstructible</a> and <a "../utility/Assignable.html">Assignable</a> requirements were forgotten in
href="../utility/Assignable.html">Assignable</a> requirements were the SGI STL documentation (try removing those archetypes). The Boost
forgotten in the SGI STL documentation (try removing those archetype classes have been designed so that they can be layered. In this
archetypes). The Boost archetype classes have been designed so that example the value type of the iterator is composed out of three archetypes.
they can be layered. In this example the value type of the iterator In the <a href="reference.htm#basic-archetype">archetype class
is composed out of three archetypes. In the archetype class reference reference</a>, template parameters named <tt>Base</tt> indicate where the
below, template parameters named <tt>Base</tt> indicate where the layered archetype paradigm can be used.</p>
layered archetype can be used. <pre>
{
<pre> typedef less_than_comparable_archetype&lt;
{ sgi_assignable_archetype&lt;&gt; &gt; ValueType;
typedef less_than_comparable_archetype&lt; random_access_iterator_archetype&lt;ValueType&gt; ri;
sgi_assignable_archetype&lt;&gt; &gt; ValueType; std::stable_sort(ri, ri);
random_access_iterator_archetype&lt;ValueType&gt; ri; }
std::stable_sort(ri, ri);
}
</pre> </pre>
<a href="./prog_with_concepts.htm">Next: Programming with Concepts</a><br> <p><a href="./prog_with_concepts.htm">Next: Programming with
<a href="./creating_concepts.htm">Prev: Creating Concept Checking Classes</a> Concepts</a><br />
<a href="./creating_concepts.htm">Prev: Creating Concept Checking
Classes</a><br />
<hr />
<br> <table>
<HR> <tr valign="top">
<TABLE> <td nowrap="nowrap">Copyright &copy; 2000</td>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY> <td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
</HTML> "mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>),
2007 <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.
</tr>
</table>
</body>
</html>

View File

@ -1,110 +1,157 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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>Creating Concept Checking Classes</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
<h2><a name="creating-concept-checks">Creating Concept Checking Classes</a></h2> <title>Creating Concept Checking Classes</title>
<link rel="stylesheet" href="../../rst.css" type="text/css" />
</head>
As an example of how to create a concept checking class, we look <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
at how to create the corresponding checks for the "#FF0000">
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> <img src="../../boost.png" alt="C++ Boost" width="277" height=
RandomAccessIterator</a> concept. First, as a convention we name the "86" /><br clear="none" />
concept checking class after the concept, and add the suffix
``<tt>Concept</tt>''. Next we must define a member function named
<tt>constraints()</tt> in which we will exercise the valid expressions
of the concept. <tt>function_requires()</tt> 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> <h2><a name="creating-concept-checks" id="creating-concept-checks">Creating
The first part of the <tt>constraints()</tt> function includes Concept Checking Classes</a></h2>
the requirements that correspond to the <i>refinement</i> relationship
between <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
RandomAccessIterator</a> and the concepts which it builds upon:
<a href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
BidirectionalIterator</a> and
<a href="http://www.sgi.com/tech/stl/LessThanComparable.html">
LessThanComparable</a>. We could have instead used
<tt>BOOST_CLASS_REQUIRE</tt> and placed these requirements in the class
body, however <tt>BOOST_CLASS_REQUIRE</tt> uses C++ language features that
are less portable.
<p> <p>As an example of how to create a concept checking class template, we
Next we check that the <tt>iterator_category</tt> of the iterator is look at how to create the corresponding checks for the <a href=
either <tt>std::random_access_iterator_tag</tt> or a derived class. "http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> concept.
After that we write out some code that corresponds to the valid The complete definition is here:</p>
expressions of the <a <pre>
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> template &lt;class X&gt;
RandomAccessIterator</a> concept. Typedefs can also be added to struct InputIterator
enforce the associated types of the concept. : Assignable&lt;X&gt;, EqualityComparable&lt;X&gt;
{
private:
typedef std::iterator_traits&lt;X&gt; t;
public:
typedef typename t::value_type value_type;
typedef typename t::difference_type difference_type;
typedef typename t::reference reference;
typedef typename t::pointer pointer;
typedef typename t::iterator_category iterator_category;
<pre> BOOST_CONCEPT_ASSERT((SignedInteger&lt;difference_type&gt;));
template &lt;class Iter&gt; BOOST_CONCEPT_ASSERT((Convertible&lt;iterator_category, std::input_iterator_tag&gt;));
struct RandomAccessIteratorConcept
{ BOOST_CONCEPT_USAGE(InputIterator)
void constraints() { {
function_requires&lt; BidirectionalIteratorConcept&lt;Iter&gt; &gt;(); X j(i); <font color=
function_requires&lt; LessThanComparableConcept&lt;Iter&gt; &gt;(); "green">// require copy construction</font>
function_requires&lt; ConvertibleConcept&lt; same_type(*i++,v); <font color=
typename std::iterator_traits&lt;Iter&gt;::iterator_category, "green">// require postincrement-dereference returning value_type</font>
std::random_access_iterator_tag&gt; &gt;(); X&amp; x = ++j; <font color=
"green">// require preincrement returning X&amp;</font>
i += n;
i = i + n; i = n + i;
i -= n;
i = i - n;
n = i - j;
i[n];
} }
Iter i, j;
typename std::iterator_traits&lt;Iter&gt;::difference_type n; private:
}; X i;
value_type v;
<font color=
"green">// Type deduction will fail unless the arguments have the same type.</font>
template &lt;typename T&gt;
void same_type(T const&amp;, T const&amp;);
};
</pre>
<h3>Walkthrough</h3>
<p>First, as a convention we name the concept checking class after the
concept. Next, since InputIterator is a refinement of Assignable and
EqualityComparable, we derive its concept checking class from the checking
classes for those other concepts. The library will automatically check for
conformance to Assignable and EqualityComparable whenever it checks the
InputIterator concept.</p>
<p>Next, we declare the concept's <a href=
"../../more/generic_programming.html#associated_type">associated types</a>
as member typedefs. The associated difference type is required to be a
signed integer, and the iterator category has to be convertible to
std::input_iterator_tag, so we assert those relationships. The syntax for
accessing associated types through the concept-checking template mirrors
the <a href=
"http://www.generic-programming.org/languages/conceptcpp/">proposed</a>
syntax for associated type access in C++0x Finally, we use the
<code>BOOST_CONCEPT_USAGE</code> macro to declare the function that
exercises all the concept's valid expressions. Note that at this point you
may sometimes need to be a little creative: for example, to check that
<code>*i++</code> returns the iterator's value type, we pass both values to
the <code>same_type</code> member function template, which requires both
arguments to have the same type, modulo references and cv-qualification.
It's an imperfect check, but it's better than nothing.</p>
<h3>Values for Usage Patterns Should Be Data Members</h3>
<p>You may be wondering why we declared <code>i</code> and <code>v</code>
as data members in the example above. Why didn't we simply write the
following?</p>
<pre>
BOOST_CONCEPT_USAGE(InputIterator)
{
X i; <font color=
"green">// create the values we need</font>
value_type v;
X j(i); <font color=
"green">// require copy construction</font>
same_type(*i++,v); <font color=
"green">// require postincrement-dereference returning value_type</font>
X&amp; x = ++j; <font color=
"green">// require preincrement returning X&amp;</font>
} }
</pre> </pre>
One potential pitfall in designing concept checking classes is using <p>Unfortunately, that code wouldn't have worked out so well, because it
more expressions in the constraint function than necessary. For unintentionally imposes the requirement that <code>X</code> and its value
example, it is easy to accidentally use the default constructor to type are both default-constructible. On the other hand, since instances of
create the objects that will be needed in the expressions (and not all the <code>InputIterator</code> template will never be constructed, the
concepts require a default constructor). This is the reason we write compiler never has to check how its data members will be constructed (C++
the constraint function as a member function of a class. The objects Standard Section 14.7.1 9). For that reason you should <strong>always
involved in the expressions are declared as data members of the class. declare values needed for usage patterns as data members</strong>.</p>
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).
<p> <p>These sorts of errors in concept definitions can be detected by the use
<a href="./concept_covering.htm">Next: Concept Covering and Archetypes</a><br> of <a href="concept_covering.htm">Concept Archetypes</a>, but it's always
<a href="./using_concept_check.htm">Prev: Using Concept Checks</a> better to avoid them pre-emptively.</p>
<h3>Similarity to Proposed C++0x Language Support for Concepts</h3>
<br> <p>This library's syntaxes for concept refinement and for access of
<HR> associated types mirrors the corresponding <a href=
<TABLE> "http://www.generic-programming.org/languages/conceptcpp/">proposed</a>
<TR valign=top> syntaxes in C++0x. However, C++0x will use
<TD nowrap>Copyright &copy 2000</TD><TD> “signatures” rather than usage patterns to
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A describe the valid operations on types participating in a concept, so when
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>) converting your concept checking classes into language-supported concepts,
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>) you'll need to translate your usage function into a series of
</TD></TR></TABLE> signatures.</p>
</BODY> <p><a href="./concept_covering.htm">Next: Concept Covering and
</HTML> Archetypes</a><br />
<a href="./using_concept_check.htm">Prev: Using Concept
Checks</a><br /></p>
<hr />
<table>
<tr valign="top">
<td nowrap="nowrap">Copyright &copy; 2000</td>
<td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
"mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>),
2007 <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.
</tr>
</table>
</body>
</html>

View File

@ -13,7 +13,7 @@ namespace fake
using namespace boost; using namespace boost;
template<typename RanIter> template<typename RanIter>
BOOST_CONCEPT_WHERE( BOOST_CONCEPT_REQUIRES(
((Mutable_RandomAccessIterator<RanIter>)) ((Mutable_RandomAccessIterator<RanIter>))
((LessThanComparable<typename Mutable_RandomAccessIterator<RanIter>::value_type>)) ((LessThanComparable<typename Mutable_RandomAccessIterator<RanIter>::value_type>))

View File

@ -1,50 +1,59 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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 Implementation</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000, David Abrahams 2007 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../../rst.css" type="text/css" />
<h2><a name="implementation">Implementation</a></h2> <title>Concept Checking Implementation</title>
</head>
Ideally we would like to catch, and indicate, the concept violation at <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
the point of instantiation. As mentioned in D&amp;E[<a "#FF0000">
href="bibliography.htm#stroustrup94:_design_evolution">2</a>], the error <img src="../../boost.png" alt="C++ Boost" width="277" height=
can be caught by exercising all of the requirements needed by the "86" /><br clear="none" />
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> <h2><a name="warning" id="warning"><font color=
"red">Warning</font></a></h2>
<p><font color="red">This documentation is out-of-date; similar but
newer implementation techniques are now used. This documentation
also refers to components and protocols in the library's old
interace such as <code>BOOST_CLASS_REQUIRES</code>
and <code>constraints()</code> functions, which are still supported
but deprecated.</font></p>
<h2><a name="implementation" id="implementation">Implementation</a></h2>
<p>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.htm#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:</p>
<pre>
template &lt;class RandomAccessIterator&gt; template &lt;class RandomAccessIterator&gt;
void stable_sort_constraints(RandomAccessIterator i) void stable_sort_constraints(RandomAccessIterator i)
{ {
@ -57,24 +66,23 @@ can be applied to the <tt>std::stable_sort()</tt> function:
void stable_sort(RandomAccessIterator first, RandomAccessIterator last) void stable_sort(RandomAccessIterator first, RandomAccessIterator last)
{ {
typedef void (*fptr_type)(RandomAccessIterator); typedef void (*fptr_type)(RandomAccessIterator);
fptr_type x = &stable_sort_constraints; fptr_type x = &amp;stable_sort_constraints;
... ...
} }
</pre> </pre>
There is often a large set of requirements that need to be checked, <p>There is often a large set of requirements that need to be checked, and
and it would be cumbersome for the library implementor to write it would be cumbersome for the library implementor to write constraint
constraint functions like <tt>stable_sort_constraints()</tt> for every functions like <tt>stable_sort_constraints()</tt> for every public
public function. Instead, we group sets of valid expressions function. Instead, we group sets of valid expressions together, according
together, according to the definitions of the corresponding concepts. to the definitions of the corresponding concepts. For each concept we
For each concept we define a concept checking class template where the define a concept checking class template where the template parameter is
template parameter is for the type to be checked. The class contains for the type to be checked. The class contains a <tt>contraints()</tt>
a <tt>contraints()</tt> member function which exercises all of the member function which exercises all of the valid expressions of the
valid expressions of the concept. The objects used in the constraints concept. The objects used in the constraints function, such as <tt>n</tt>
function, such as <tt>n</tt> and <tt>i</tt>, are declared as data and <tt>i</tt>, are declared as data members of the concept checking
members of the concept checking class. class.</p>
<pre>
<pre>
template &lt;class Iter&gt; template &lt;class Iter&gt;
struct RandomAccessIteratorConcept struct RandomAccessIteratorConcept
{ {
@ -90,18 +98,14 @@ members of the concept checking class.
}; };
</pre> </pre>
We can still use the function pointer mechanism to cause instantiation <p>We can still use the function pointer mechanism to cause instantiation
of the constraints function, however now it will be a member function of the constraints function, however now it will be a member function
pointer. To make it easy for the library implementor to invoke the pointer. To make it easy for the library implementor to invoke the concept
concept checks, we wrap the member function pointer mechanism in a checks, we wrap the member function pointer mechanism in a function named
function named <tt>function_requires()</tt>. The following code <tt>function_requires()</tt>. The following code snippet shows how to use
snippet shows how to use <tt>function_requires()</tt> to make sure <tt>function_requires()</tt> to make sure that the iterator is a <a href=
that the iterator is a "http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a>.</p>
<a <pre>
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
RandomAccessIterator</a>.
<pre>
template &lt;class Iter&gt; template &lt;class Iter&gt;
void stable_sort(Iter first, Iter last) void stable_sort(Iter first, Iter last)
{ {
@ -110,16 +114,15 @@ RandomAccessIterator</a>.
} }
</pre> </pre>
The definition of the <tt>function_requires()</tt> is as follows. The <p>The definition of the <tt>function_requires()</tt> is as follows. The
<tt>Concept</tt> is the concept checking class that has been <tt>Concept</tt> is the concept checking class that has been instantiated
instantiated with the modeling type. We assign the address of the with the modeling type. We assign the address of the constraints member
constraints member function to the function pointer <tt>x</tt>, which function to the function pointer <tt>x</tt>, which causes the instantiation
causes the instantiation of the constraints function and checking of of the constraints function and checking of the concept's valid
the concept's valid expressions. We then assign <tt>x</tt> to expressions. We then assign <tt>x</tt> to <tt>x</tt> to avoid unused
<tt>x</tt> to avoid unused variable compiler warnings, and wrap variable compiler warnings, and wrap everything in a do-while loop to
everything in a do-while loop to prevent name collisions. prevent name collisions.</p>
<pre>
<pre>
template &lt;class Concept&gt; template &lt;class Concept&gt;
void function_requires() void function_requires()
{ {
@ -128,17 +131,16 @@ everything in a do-while loop to prevent name collisions.
} }
</pre> </pre>
To check the type parameters of class templates, we provide the <p>To check the type parameters of class templates, we provide the
<tt>BOOST_CLASS_REQUIRE</tt> macro which can be used inside the body of a <tt>BOOST_CLASS_REQUIRE</tt> macro which can be used inside the body of a
class definition (whereas <tt>function_requires()</tt> can only be used class definition (whereas <tt>function_requires()</tt> can only be used
inside of a function body). This macro declares a nested class inside of a function body). This macro declares a nested class template,
template, where the template parameter is a function pointer. We then where the template parameter is a function pointer. We then use the nested
use the nested class type in a typedef with the function pointer type class type in a typedef with the function pointer type of the constraint
of the constraint function as the template argument. We use the function as the template argument. We use the <tt>type_var</tt> and
<tt>type_var</tt> and <tt>concept</tt> names in the nested class and <tt>concept</tt> names in the nested class and typedef names to help
typedef names to help prevent name collisions. prevent name collisions.</p>
<pre>
<pre>
#define BOOST_CLASS_REQUIRE(type_var, ns, concept) \ #define BOOST_CLASS_REQUIRE(type_var, ns, concept) \
typedef void (ns::concept &lt;type_var&gt;::* func##type_var##concept)(); \ typedef void (ns::concept &lt;type_var&gt;::* func##type_var##concept)(); \
template &lt;func##type_var##concept _Tp1&gt; \ template &lt;func##type_var##concept _Tp1&gt; \
@ -148,14 +150,12 @@ typedef names to help prevent name collisions.
concept_checking_typedef_##type_var##concept concept_checking_typedef_##type_var##concept
</pre> </pre>
In addition, there are versions of <tt>BOOST_CLASS_REQUIRE</tt> that <p>In addition, there are versions of <tt>BOOST_CLASS_REQUIRE</tt> that
take more arguments, to handle concepts that include interactions take more arguments, to handle concepts that include interactions between
between two or more types. <tt>BOOST_CLASS_REQUIRE</tt> was not used two or more types. <tt>BOOST_CLASS_REQUIRE</tt> was not used in the
in the implementation of the BCCL concept checks because some implementation of the BCCL concept checks because some compilers do not
compilers do not implement template parameters of function pointer implement template parameters of function pointer type.
type. <!-- We decided not to go with this version since it is easier to misuse
<!-- We decided not to go with this version since it is easier to misuse
To check the type parameters of class templates, we provide the 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 <tt>class_requires</tt> class which can be used inside the body of a
@ -184,21 +184,22 @@ Boost Concept Checking Library concept checks because several
compilers do not implement template parameters of function pointer compilers do not implement template parameters of function pointer
type. type.
--> --></p>
<p> <p><a href="./reference.htm">Next: Reference</a><br />
<a href="./reference.htm">Next: Reference</a><br> <a href="prog_with_concepts.htm">Prev: Programming With
<a href="prog_with_concepts.htm">Prev: Programming With Concepts</a> Concepts</a><br /></p>
<hr />
<br> <table>
<HR> <tr valign="top">
<TABLE> <td nowrap="nowrap">Copyright &copy; 2000</td>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY> <td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
</HTML> "mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>),
2007 <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.
</tr>
</table>
</body>
</html>

View File

@ -21,9 +21,20 @@ struct usage_requirements
~usage_requirements() { ((Model*)0)->~Model(); } ~usage_requirements() { ((Model*)0)->~Model(); }
}; };
# define BOOST_CONCEPT_USAGE(model) \ # if BOOST_WORKAROUND(__GNUC__, <= 3)
BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements<model>)); \
~model() # define BOOST_CONCEPT_USAGE(model) \
model(); /* at least 2.96 and 3.4.3 both need this :( */ \
BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements<model>)); \
~model()
# else
# define BOOST_CONCEPT_USAGE(model) \
BOOST_CONCEPT_ASSERT((boost::concept::usage_requirements<model>)); \
~model()
# endif
# endif # endif

View File

@ -1,8 +1,8 @@
// Copyright David Abrahams 2006. Distributed under the Boost // Copyright David Abrahams 2006. Distributed under the Boost
// Software License, Version 1.0. (See accompanying // Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONCEPT_WHERE_DWA2006430_HPP #ifndef BOOST_CONCEPT_REQUIRES_DWA2006430_HPP
# define BOOST_CONCEPT_WHERE_DWA2006430_HPP # define BOOST_CONCEPT_REQUIRES_DWA2006430_HPP
# include <boost/parameter/aux_/parenthesized_type.hpp> # include <boost/parameter/aux_/parenthesized_type.hpp>
# include <boost/concept/assert.hpp> # include <boost/concept/assert.hpp>
@ -12,7 +12,7 @@ namespace boost {
// Template for use in handwritten assertions // Template for use in handwritten assertions
template <class Model, class More> template <class Model, class More>
struct where_ : More struct requires_ : More
{ {
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
typedef typename More::type type; typedef typename More::type type;
@ -23,41 +23,52 @@ struct where_ : More
// Template for use by macros, where models must be wrapped in parens. // Template for use by macros, where models must be wrapped in parens.
// This isn't in namespace detail to keep extra cruft out of resulting // This isn't in namespace detail to keep extra cruft out of resulting
// error messages. // error messages.
template <class ModelFn, class More> template <class ModelFn>
struct _where_ : More struct _requires_
{ {
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) enum { value = 0 };
typedef typename More::type type;
# endif
BOOST_CONCEPT_ASSERT_FN(ModelFn); BOOST_CONCEPT_ASSERT_FN(ModelFn);
}; };
#define BOOST_CONCEPT_WHERE_OPEN(r,data,t) ::boost::_where_<void(*)t, template <int check, class Result>
#define BOOST_CONCEPT_WHERE_CLOSE(r,data,t) > struct Requires_ : ::boost::parameter::aux::unaryfunptr_arg_type<Result>
{
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
typedef typename ::boost::parameter::aux::unaryfunptr_arg_type<Result>::type type;
# endif
};
#define BOOST_CONCEPT_REQUIRES_(r,data,t) + (::boost::_requires_<void(*)t>::value)
#if defined(NDEBUG) || BOOST_WORKAROUND(BOOST_MSVC, < 1300) #if defined(NDEBUG) || BOOST_WORKAROUND(BOOST_MSVC, < 1300)
# define BOOST_CONCEPT_WHERE(models, result) \ # define BOOST_CONCEPT_REQUIRES(models, result) \
typename ::boost::parameter::aux::unaryfunptr_arg_type<void(*)result>::type typename ::boost::parameter::aux::unaryfunptr_arg_type<void(*)result>::type
#elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) #elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// Same thing as below without the initial typename // Same thing as below without the initial typename
# define BOOST_CONCEPT_WHERE(models, result) \ # define BOOST_CONCEPT_REQUIRES(models, result) \
BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_OPEN, ~, models) \ ::boost::Requires_< \
(0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \
::boost::parameter::aux::unaryfunptr_arg_type<void(*)result> \ ::boost::parameter::aux::unaryfunptr_arg_type<void(*)result> \
BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_CLOSE, ~, models)::type >::type
#else #else
// This just ICEs on MSVC6 :( // This just ICEs on MSVC6 :(
# define BOOST_CONCEPT_WHERE(models, result) \ # define BOOST_CONCEPT_REQUIRES(models, result) \
typename BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_OPEN, ~, models) \ typename ::boost::Requires_< \
::boost::parameter::aux::unaryfunptr_arg_type<void(*)result> \ (0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \
BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_WHERE_CLOSE, ~, models)::type void(*)result \
>::type
#endif #endif
// C++0x proposed syntax changed. This supports an older usage
#define BOOST_CONCEPT_WHERE(models,result) BOOST_CONCEPT_REQUIRES(models,result)
} // namespace boost::concept_check } // namespace boost::concept_check
#endif // BOOST_CONCEPT_WHERE_DWA2006430_HPP #endif // BOOST_CONCEPT_REQUIRES_DWA2006430_HPP

View File

@ -62,9 +62,6 @@ namespace boost
// //
BOOST_concept(Integer, (T)) BOOST_concept(Integer, (T))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Integer(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Integer) BOOST_CONCEPT_USAGE(Integer)
{ {
x.error_type_must_be_an_integer_type(); x.error_type_must_be_an_integer_type();
@ -90,9 +87,6 @@ namespace boost
# endif # endif
BOOST_concept(SignedInteger,(T)) { BOOST_concept(SignedInteger,(T)) {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
SignedInteger(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(SignedInteger) { BOOST_CONCEPT_USAGE(SignedInteger) {
x.error_type_must_be_a_signed_integer_type(); x.error_type_must_be_a_signed_integer_type();
} }
@ -110,9 +104,6 @@ namespace boost
# endif # endif
BOOST_concept(UnsignedInteger,(T)) { BOOST_concept(UnsignedInteger,(T)) {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
UnsignedInteger(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(UnsignedInteger) { BOOST_CONCEPT_USAGE(UnsignedInteger) {
x.error_type_must_be_an_unsigned_integer_type(); x.error_type_must_be_an_unsigned_integer_type();
} }
@ -135,9 +126,6 @@ namespace boost
BOOST_concept(DefaultConstructible,(TT)) BOOST_concept(DefaultConstructible,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
DefaultConstructible(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(DefaultConstructible) { BOOST_CONCEPT_USAGE(DefaultConstructible) {
TT a; // require default constructor TT a; // require default constructor
ignore_unused_variable_warning(a); ignore_unused_variable_warning(a);
@ -146,13 +134,9 @@ namespace boost
BOOST_concept(Assignable,(TT)) BOOST_concept(Assignable,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Assignable(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Assignable) { BOOST_CONCEPT_USAGE(Assignable) {
#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL #if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL
a = a; // require assignment operator a = a; // require assignment operator
#endif #endif
const_constraints(a); const_constraints(a);
} }
@ -166,12 +150,9 @@ namespace boost
TT a; TT a;
}; };
BOOST_concept(CopyConstructible,(TT)) BOOST_concept(CopyConstructible,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
CopyConstructible(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(CopyConstructible) { BOOST_CONCEPT_USAGE(CopyConstructible) {
TT a(b); // require copy constructor TT a(b); // require copy constructor
TT* ptr = &a; // require address of operator TT* ptr = &a; // require address of operator
@ -191,10 +172,6 @@ namespace boost
// The SGI STL version of Assignable requires copy constructor and operator= // The SGI STL version of Assignable requires copy constructor and operator=
BOOST_concept(SGIAssignable,(TT)) BOOST_concept(SGIAssignable,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
SGIAssignable(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(SGIAssignable) { BOOST_CONCEPT_USAGE(SGIAssignable) {
TT b(a); TT b(a);
#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL #if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL
@ -216,9 +193,6 @@ namespace boost
BOOST_concept(Convertible,(X)(Y)) BOOST_concept(Convertible,(X)(Y))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Convertible(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Convertible) { BOOST_CONCEPT_USAGE(Convertible) {
Y y = x; Y y = x;
ignore_unused_variable_warning(y); ignore_unused_variable_warning(y);
@ -244,9 +218,6 @@ namespace boost
BOOST_concept(EqualityComparable,(TT)) BOOST_concept(EqualityComparable,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
EqualityComparable(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(EqualityComparable) { BOOST_CONCEPT_USAGE(EqualityComparable) {
require_boolean_expr(a == b); require_boolean_expr(a == b);
require_boolean_expr(a != b); require_boolean_expr(a != b);
@ -257,9 +228,6 @@ namespace boost
BOOST_concept(LessThanComparable,(TT)) BOOST_concept(LessThanComparable,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
LessThanComparable(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(LessThanComparable) { BOOST_CONCEPT_USAGE(LessThanComparable) {
require_boolean_expr(a < b); require_boolean_expr(a < b);
} }
@ -270,9 +238,6 @@ namespace boost
// This is equivalent to SGI STL's LessThanComparable. // This is equivalent to SGI STL's LessThanComparable.
BOOST_concept(Comparable,(TT)) BOOST_concept(Comparable,(TT))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Comparable(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Comparable) { BOOST_CONCEPT_USAGE(Comparable) {
require_boolean_expr(a < b); require_boolean_expr(a < b);
require_boolean_expr(a > b); require_boolean_expr(a > b);
@ -283,18 +248,6 @@ namespace boost
TT a, b; TT a, b;
}; };
#if BOOST_WORKAROUND(__GNUC__, <= 3)
#define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \
BOOST_concept(NAME, (First)(Second)) \
{ \
NAME(); \
BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \
private: \
bool constraints_() { return a OP b; } \
First a; \
Second b; \
}
#else
#define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \ #define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \
BOOST_concept(NAME, (First)(Second)) \ BOOST_concept(NAME, (First)(Second)) \
{ \ { \
@ -304,20 +257,7 @@ namespace boost
First a; \ First a; \
Second b; \ Second b; \
} }
#endif
#if BOOST_WORKAROUND(__GNUC__, <= 3)
#define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \
BOOST_concept(NAME, (Ret)(First)(Second)) \
{ \
NAME(); \
BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \
private: \
Ret constraints_() { return a OP b; } \
First a; \
Second b; \
}
#else
#define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \ #define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \
BOOST_concept(NAME, (Ret)(First)(Second)) \ BOOST_concept(NAME, (Ret)(First)(Second)) \
{ \ { \
@ -327,7 +267,6 @@ namespace boost
First a; \ First a; \
Second b; \ Second b; \
} }
#endif
BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(==, EqualOp); BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(==, EqualOp);
BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(!=, NotEqualOp); BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(!=, NotEqualOp);
@ -347,9 +286,6 @@ namespace boost
BOOST_concept(Generator,(Func)(Return)) BOOST_concept(Generator,(Func)(Return))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Generator(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Generator) { test(is_void<Return>()); } BOOST_CONCEPT_USAGE(Generator) { test(is_void<Return>()); }
private: private:
@ -370,9 +306,6 @@ namespace boost
BOOST_concept(UnaryFunction,(Func)(Return)(Arg)) BOOST_concept(UnaryFunction,(Func)(Return)(Arg))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
UnaryFunction(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void<Return>()); } BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void<Return>()); }
private: private:
@ -394,9 +327,6 @@ namespace boost
BOOST_concept(BinaryFunction,(Func)(Return)(First)(Second)) BOOST_concept(BinaryFunction,(Func)(Return)(First)(Second))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
BinaryFunction(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(BinaryFunction) { test(is_void<Return>()); } BOOST_CONCEPT_USAGE(BinaryFunction) { test(is_void<Return>()); }
private: private:
void test(boost::mpl::false_) void test(boost::mpl::false_)
@ -418,9 +348,6 @@ namespace boost
BOOST_concept(UnaryPredicate,(Func)(Arg)) BOOST_concept(UnaryPredicate,(Func)(Arg))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
UnaryPredicate(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(UnaryPredicate) { BOOST_CONCEPT_USAGE(UnaryPredicate) {
require_boolean_expr(f(arg)); // require operator() returning bool require_boolean_expr(f(arg)); // require operator() returning bool
} }
@ -431,9 +358,6 @@ namespace boost
BOOST_concept(BinaryPredicate,(Func)(First)(Second)) BOOST_concept(BinaryPredicate,(Func)(First)(Second))
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
BinaryPredicate(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(BinaryPredicate) { BOOST_CONCEPT_USAGE(BinaryPredicate) {
require_boolean_expr(f(a, b)); // require operator() returning bool require_boolean_expr(f(a, b)); // require operator() returning bool
} }
@ -447,9 +371,6 @@ namespace boost
BOOST_concept(Const_BinaryPredicate,(Func)(First)(Second)) BOOST_concept(Const_BinaryPredicate,(Func)(First)(Second))
: BinaryPredicate<Func, First, Second> : BinaryPredicate<Func, First, Second>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
Const_BinaryPredicate(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(Const_BinaryPredicate) { BOOST_CONCEPT_USAGE(Const_BinaryPredicate) {
const_constraints(f); const_constraints(f);
} }
@ -468,9 +389,6 @@ namespace boost
{ {
typedef typename Func::result_type result_type; typedef typename Func::result_type result_type;
#if BOOST_WORKAROUND(__GNUC__, <= 3)
AdaptableGenerator(); // at least 2.96 and 3.4.3 both need this :(
#endif
BOOST_CONCEPT_USAGE(AdaptableGenerator) BOOST_CONCEPT_USAGE(AdaptableGenerator)
{ {
BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>)); BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>));
@ -483,9 +401,6 @@ namespace boost
typedef typename Func::argument_type argument_type; typedef typename Func::argument_type argument_type;
typedef typename Func::result_type result_type; typedef typename Func::result_type result_type;
#if BOOST_WORKAROUND(__GNUC__, <= 3)
AdaptableUnaryFunction(); // at least 2.96 and 3.4.3 both need this :(
#endif
~AdaptableUnaryFunction() ~AdaptableUnaryFunction()
{ {
BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>)); BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>));
@ -505,9 +420,6 @@ namespace boost
typedef typename Func::second_argument_type second_argument_type; typedef typename Func::second_argument_type second_argument_type;
typedef typename Func::result_type result_type; typedef typename Func::result_type result_type;
#if BOOST_WORKAROUND(__GNUC__, <= 3)
AdaptableBinaryFunction(); // at least 2.96 and 3.4.3 both need this :(
#endif
~AdaptableBinaryFunction() ~AdaptableBinaryFunction()
{ {
BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>)); BOOST_CONCEPT_ASSERT((Convertible<result_type, Return>));
@ -520,18 +432,12 @@ namespace boost
: UnaryPredicate<Func, Arg> : UnaryPredicate<Func, Arg>
, AdaptableUnaryFunction<Func, bool, Arg> , AdaptableUnaryFunction<Func, bool, Arg>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
AdaptablePredicate(); // at least 2.96 and 3.4.3 both need this :(
#endif
}; };
BOOST_concept(AdaptableBinaryPredicate,(Func)(First)(Second)) BOOST_concept(AdaptableBinaryPredicate,(Func)(First)(Second))
: BinaryPredicate<Func, First, Second> : BinaryPredicate<Func, First, Second>
, AdaptableBinaryFunction<Func, bool, First, Second> , AdaptableBinaryFunction<Func, bool, First, Second>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3)
AdaptableBinaryPredicate(); // at least 2.96 and 3.4.3 both need this :(
#endif
}; };
//=========================================================================== //===========================================================================
@ -547,10 +453,7 @@ namespace boost
typedef typename boost::detail::iterator_traits<TT>::pointer pointer; typedef typename boost::detail::iterator_traits<TT>::pointer pointer;
typedef typename boost::detail::iterator_traits<TT>::iterator_category iterator_category; typedef typename boost::detail::iterator_traits<TT>::iterator_category iterator_category;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(InputIterator)
InputIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~InputIterator()
{ {
BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>)); BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>)); BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));
@ -567,10 +470,7 @@ namespace boost
BOOST_concept(OutputIterator,(TT)(ValueT)) BOOST_concept(OutputIterator,(TT)(ValueT))
: Assignable<TT> : Assignable<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(OutputIterator) {
OutputIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~OutputIterator() {
++i; // require preincrement operator ++i; // require preincrement operator
i++; // require postincrement operator i++; // require postincrement operator
@ -584,10 +484,7 @@ namespace boost
BOOST_concept(ForwardIterator,(TT)) BOOST_concept(ForwardIterator,(TT))
: InputIterator<TT> : InputIterator<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(ForwardIterator)
ForwardIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~ForwardIterator()
{ {
BOOST_CONCEPT_ASSERT((Convertible< BOOST_CONCEPT_ASSERT((Convertible<
BOOST_DEDUCED_TYPENAME ForwardIterator::iterator_category BOOST_DEDUCED_TYPENAME ForwardIterator::iterator_category
@ -605,10 +502,7 @@ namespace boost
BOOST_concept(Mutable_ForwardIterator,(TT)) BOOST_concept(Mutable_ForwardIterator,(TT))
: ForwardIterator<TT> : ForwardIterator<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_ForwardIterator) {
Mutable_ForwardIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_ForwardIterator() {
*i++ = *i; // require postincrement and assignment *i++ = *i; // require postincrement and assignment
} }
private: private:
@ -618,10 +512,7 @@ namespace boost
BOOST_concept(BidirectionalIterator,(TT)) BOOST_concept(BidirectionalIterator,(TT))
: ForwardIterator<TT> : ForwardIterator<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(BidirectionalIterator)
BidirectionalIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~BidirectionalIterator()
{ {
BOOST_CONCEPT_ASSERT((Convertible< BOOST_CONCEPT_ASSERT((Convertible<
BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category
@ -639,10 +530,7 @@ namespace boost
: BidirectionalIterator<TT> : BidirectionalIterator<TT>
, Mutable_ForwardIterator<TT> , Mutable_ForwardIterator<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_BidirectionalIterator)
Mutable_BidirectionalIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_BidirectionalIterator()
{ {
*i-- = *i; // require postdecrement and assignment *i-- = *i; // require postdecrement and assignment
} }
@ -654,10 +542,7 @@ namespace boost
: BidirectionalIterator<TT> : BidirectionalIterator<TT>
, Comparable<TT> , Comparable<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(RandomAccessIterator)
RandomAccessIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~RandomAccessIterator()
{ {
BOOST_CONCEPT_ASSERT((Convertible< BOOST_CONCEPT_ASSERT((Convertible<
BOOST_DEDUCED_TYPENAME BidirectionalIterator<TT>::iterator_category BOOST_DEDUCED_TYPENAME BidirectionalIterator<TT>::iterator_category
@ -682,10 +567,7 @@ namespace boost
: RandomAccessIterator<TT> : RandomAccessIterator<TT>
, Mutable_BidirectionalIterator<TT> , Mutable_BidirectionalIterator<TT>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_RandomAccessIterator)
Mutable_RandomAccessIterator(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_RandomAccessIterator()
{ {
i[n] = *i; // require element access and assignment i[n] = *i; // require element access and assignment
} }
@ -707,10 +589,7 @@ namespace boost
typedef typename C::const_pointer const_pointer; typedef typename C::const_pointer const_pointer;
typedef typename C::const_iterator const_iterator; typedef typename C::const_iterator const_iterator;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Container)
Container(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Container()
{ {
BOOST_CONCEPT_ASSERT((InputIterator<const_iterator>)); BOOST_CONCEPT_ASSERT((InputIterator<const_iterator>));
const_constraints(c); const_constraints(c);
@ -737,10 +616,7 @@ namespace boost
typedef typename C::iterator iterator; typedef typename C::iterator iterator;
typedef typename C::pointer pointer; typedef typename C::pointer pointer;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_Container)
Mutable_Container(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_Container()
{ {
BOOST_CONCEPT_ASSERT(( BOOST_CONCEPT_ASSERT((
Assignable<typename Mutable_Container::value_type>)); Assignable<typename Mutable_Container::value_type>));
@ -760,10 +636,7 @@ namespace boost
BOOST_concept(ForwardContainer,(C)) BOOST_concept(ForwardContainer,(C))
: Container<C> : Container<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(ForwardContainer)
ForwardContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~ForwardContainer()
{ {
BOOST_CONCEPT_ASSERT(( BOOST_CONCEPT_ASSERT((
ForwardIterator< ForwardIterator<
@ -776,10 +649,7 @@ namespace boost
: ForwardContainer<C> : ForwardContainer<C>
, Mutable_Container<C> , Mutable_Container<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_ForwardContainer)
Mutable_ForwardContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_ForwardContainer()
{ {
BOOST_CONCEPT_ASSERT(( BOOST_CONCEPT_ASSERT((
Mutable_ForwardIterator< Mutable_ForwardIterator<
@ -795,10 +665,7 @@ namespace boost
C::const_reverse_iterator C::const_reverse_iterator
const_reverse_iterator; const_reverse_iterator;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(ReversibleContainer)
ReversibleContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~ReversibleContainer()
{ {
BOOST_CONCEPT_ASSERT(( BOOST_CONCEPT_ASSERT((
BidirectionalIterator< BidirectionalIterator<
@ -823,10 +690,7 @@ namespace boost
{ {
typedef typename C::reverse_iterator reverse_iterator; typedef typename C::reverse_iterator reverse_iterator;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_ReversibleContainer)
Mutable_ReversibleContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_ReversibleContainer()
{ {
typedef typename Mutable_ForwardContainer<C>::iterator iterator; typedef typename Mutable_ForwardContainer<C>::iterator iterator;
BOOST_CONCEPT_ASSERT((Mutable_BidirectionalIterator<iterator>)); BOOST_CONCEPT_ASSERT((Mutable_BidirectionalIterator<iterator>));
@ -845,10 +709,7 @@ namespace boost
typedef typename C::size_type size_type; typedef typename C::size_type size_type;
typedef typename C::const_reference const_reference; typedef typename C::const_reference const_reference;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(RandomAccessContainer)
RandomAccessContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~RandomAccessContainer()
{ {
BOOST_CONCEPT_ASSERT(( BOOST_CONCEPT_ASSERT((
RandomAccessIterator< RandomAccessIterator<
@ -875,10 +736,7 @@ namespace boost
private: private:
typedef Mutable_RandomAccessContainer self; typedef Mutable_RandomAccessContainer self;
public: public:
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Mutable_RandomAccessContainer)
Mutable_RandomAccessContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Mutable_RandomAccessContainer()
{ {
BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator<typename self::iterator>)); BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator<typename self::iterator>));
BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator<typename self::reverse_iterator>)); BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator<typename self::reverse_iterator>));
@ -900,10 +758,7 @@ namespace boost
// ... so why aren't we following the standard? --DWA // ... so why aren't we following the standard? --DWA
, DefaultConstructible<S> , DefaultConstructible<S>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(Sequence)
Sequence(); // at least 2.96 and 3.4.3 both need this :(
#endif
~Sequence()
{ {
S S
c(n), c(n),
@ -940,10 +795,7 @@ namespace boost
BOOST_concept(FrontInsertionSequence,(S)) BOOST_concept(FrontInsertionSequence,(S))
: Sequence<S> : Sequence<S>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(FrontInsertionSequence)
FrontInsertionSequence(); // at least 2.96 and 3.4.3 both need this :(
#endif
~FrontInsertionSequence()
{ {
c.push_front(t); c.push_front(t);
c.pop_front(); c.pop_front();
@ -956,10 +808,7 @@ namespace boost
BOOST_concept(BackInsertionSequence,(S)) BOOST_concept(BackInsertionSequence,(S))
: Sequence<S> : Sequence<S>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(BackInsertionSequence)
BackInsertionSequence(); // at least 2.96 and 3.4.3 both need this :(
#endif
~BackInsertionSequence()
{ {
c.push_back(t); c.push_back(t);
c.pop_back(); c.pop_back();
@ -986,10 +835,7 @@ namespace boost
typedef typename C::value_compare value_compare; typedef typename C::value_compare value_compare;
typedef typename C::iterator iterator; typedef typename C::iterator iterator;
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(AssociativeContainer)
AssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~AssociativeContainer()
{ {
i = c.find(k); i = c.find(k);
r = c.equal_range(k); r = c.equal_range(k);
@ -1025,10 +871,7 @@ namespace boost
BOOST_concept(UniqueAssociativeContainer,(C)) BOOST_concept(UniqueAssociativeContainer,(C))
: AssociativeContainer<C> : AssociativeContainer<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(UniqueAssociativeContainer)
UniqueAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~UniqueAssociativeContainer()
{ {
C c(first, last); C c(first, last);
@ -1046,10 +889,7 @@ namespace boost
BOOST_concept(MultipleAssociativeContainer,(C)) BOOST_concept(MultipleAssociativeContainer,(C))
: AssociativeContainer<C> : AssociativeContainer<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(MultipleAssociativeContainer)
MultipleAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~MultipleAssociativeContainer()
{ {
C c(first, last); C c(first, last);
@ -1068,10 +908,7 @@ namespace boost
BOOST_concept(SimpleAssociativeContainer,(C)) BOOST_concept(SimpleAssociativeContainer,(C))
: AssociativeContainer<C> : AssociativeContainer<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(SimpleAssociativeContainer)
SimpleAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~SimpleAssociativeContainer()
{ {
typedef typename C::key_type key_type; typedef typename C::key_type key_type;
typedef typename C::value_type value_type; typedef typename C::value_type value_type;
@ -1082,10 +919,7 @@ namespace boost
BOOST_concept(PairAssociativeContainer,(C)) BOOST_concept(PairAssociativeContainer,(C))
: AssociativeContainer<C> : AssociativeContainer<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(PairAssociativeContainer)
PairAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~PairAssociativeContainer()
{ {
typedef typename C::key_type key_type; typedef typename C::key_type key_type;
typedef typename C::value_type value_type; typedef typename C::value_type value_type;
@ -1099,10 +933,7 @@ namespace boost
: AssociativeContainer<C> : AssociativeContainer<C>
, ReversibleContainer<C> , ReversibleContainer<C>
{ {
#if BOOST_WORKAROUND(__GNUC__, <= 3) BOOST_CONCEPT_USAGE(SortedAssociativeContainer)
SortedAssociativeContainer(); // at least 2.96 and 3.4.3 both need this :(
#endif
~SortedAssociativeContainer()
{ {
C C
c(kc), c(kc),

View File

@ -1,57 +1,55 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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>Programming With Concepts</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<h2><a name="programming-with-concepts">Programming with Concepts</a></h2> <head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
The process of deciding how to group requirements into concepts and <title>Programming With Concepts</title>
deciding which concepts to use in each algorithm is perhaps the most <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
difficult (yet most important) part of building a generic library. <link rel="stylesheet" href="../../rst.css" type="text/css" />
A guiding principle to use during this process is one we </head>
call the <i>requirement minimization principle</i>.
<p> <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
<b>Requirement Minimization Principle:</b> Minimize the requirements "#FF0000">
on the input parameters of a component to increase its reusability. <img src="../../boost.png" alt="C++ Boost" width="277" height=
"86" /><br clear="none" />
<p> <h2><a name="programming-with-concepts" id=
There is natural tension in this statement. By definition, the input "programming-with-concepts">Programming with Concepts</a></h2>
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> <p>The process of deciding how to group requirements into concepts and
The traditional notions of <i>abstraction</i> tie in directly to the deciding which concepts to use in each algorithm is perhaps the most
idea of minimal requirements. The more abstract the input, the fewer difficult (yet most important) part of building a generic library. A
the requirements. Thus, concepts are simply the embodiment of generic guiding principle to use during this process is one we call the
abstract data types in C++ template programming. <i>requirement minimization principle</i>.</p>
<p> <p><b>Requirement Minimization Principle:</b> Minimize the requirements on
When designing the concepts for some problem domain it is important to the input parameters of a component to increase its reusability.</p>
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.
<!-- the following discussion does not match the Standard definition <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>
<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>
<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.
<!-- the following discussion does not match the Standard definition
of LessThanComparable and needs to be changed -Jeremy of LessThanComparable and needs to be changed -Jeremy
<p> <p>
@ -88,7 +86,7 @@ principle because all of the comparison operators (<tt>&lt;</tt>,
<tt>></tt>, <tt><=</tt>, <tt>>=</tt>) are conceptually equivalent (in <tt>></tt>, <tt><=</tt>, <tt>>=</tt>) are conceptually equivalent (in
a mathematical sense). Adding conceptually equivalent valid a mathematical sense). Adding conceptually equivalent valid
expressions is not a violation of the requirement minimization expressions is not a violation of the requirement minimization
principle because no new semantics are being added --- only new principle because no new semantics are being added === only new
syntax. The added syntax increases re-usability. syntax. The added syntax increases re-usability.
<p> <p>
@ -105,44 +103,42 @@ LessThanComparable</a> is given as the requirement for
<tt>std::stable_sort()</tt>, then the maintainer is given a reasonable <tt>std::stable_sort()</tt>, then the maintainer is given a reasonable
amount of flexibility within which to work. amount of flexibility within which to work.
--> --></p>
<p> <p>Minimality in concepts is a property associated with the underlying
Minimality in concepts is a property associated with the underlying semantics of the problem domain being represented. In the problem domain of
semantics of the problem domain being represented. In the problem basic containers, requiring traversal in a single direction is a smaller
domain of basic containers, requiring traversal in a single direction requirement than requiring traversal in both directions (hence the
is a smaller requirement than requiring traversal in both directions distinction between <a href=
(hence the distinction between <a "http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a> and
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> <a href=
ForwardIterator</a> and "http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>).
<a The semantic difference can be easily seen in the difference between the
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html"> set of concrete data structures that have forward iterators versus the set
BidirectionalIterator</a>). The semantic difference can be easily seen that has bidirectional iterators. For example, singly-linked lists would
in the difference between the set of concrete data structures that fall in the set of data structures having forward iterators, but not
have forward iterators versus the set that has bidirectional bidirectional iterators. In addition, the set of algorithms that one can
iterators. For example, singly-linked lists would fall in the set of implement using only forward iterators is quite different than the set that
data structures having forward iterators, but not bidirectional can be implemented with bidirectional iterators. Because of this, it is
iterators. In addition, the set of algorithms that one can implement important to factor families of requirements into rather fine-grained
using only forward iterators is quite different than the set that can concepts. For example, the requirements for iterators are factored into the
be implemented with bidirectional iterators. Because of this, it is six STL iterator concepts (trivial, output, input, forward, bidirectional,
important to factor families of requirements into rather fine-grained and random access).</p>
concepts. For example, the requirements for iterators are factored
into the six STL iterator concepts (trivial, output, input, forward,
bidirectional, and random access).
<p> <p><a href="./implementation.htm">Next: Implementation</a><br />
<a href="./implementation.htm">Next: Implementation</a><br> <a href="./concept_covering.htm">Prev: Concept Covering and
<a href="./concept_covering.htm">Prev: Concept Covering and Archetypes</a> Archetypes</a><br /></p>
<hr />
<br> <table>
<HR> <tr valign="top">
<TABLE> <td nowrap="nowrap">Copyright &copy; 2000</td>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY> <td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
</HTML> "mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>),
2007 <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.
</tr>
</table>
</body>
</html>

View File

@ -1,308 +1,391 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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>Boost Concept Checking Reference</Title>
</Head>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<h2><a name="reference">Reference</a></h2> <head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../../rst.css" type="text/css" />
<OL> <title>Boost Concept Checking Reference</title>
<LI><a href="#functions">Functions</a></LI> </head>
<LI><a href="#macros">Macros</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>
<h3><a name="functions">Functions</a></h3> <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
"#FF0000">
<img src="../../boost.png" alt="C++ Boost" width="277" height=
"86" /><br clear="none" />
<pre> <h2><a name="reference" id="reference">Reference</a></h2>
template &lt;class Concept&gt;
void function_requires(); <ol>
<li><a href="#macros">Macros</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>
<li><a href="#deprecated-functions">Deprecated Functions</a></li>
<li><a href="#deprecated-macros">Deprecated Macros</a></li>
<li><a href="#deprecated-concept-checking-classes">Deprecated Concept
Checking Classes</a></li>
</ol>
<h3><a name="macros" id="macros">Macros</a></h3>
<pre>
#include "boost/concept/assert.hpp"
BOOST_CONCEPT_ASSERT((<em>concept checking class template specialization</em>));
</pre> </pre>
<h3><a name="macros">Macros</a></h3> <p><strong>Effects:</strong> causes a compilation failure if the concept is
not satisfied.<br />
<strong>Note:</strong> this macro can be used at global, class, or function
scope.</p>
<pre> <h3><a name="basic-concepts" id="basic-concepts">Basic Concept Checking
// Apply concept checks in class definitions. Classes</a></h3>
BOOST_CLASS_REQUIRE(<i>type</i>, <i>namespace-of-concept</i>, <i>concept</i>); <pre>
BOOST_CLASS_REQUIRE2(<i>type1</i>, <i>type2</i>, <i>namespace-of-concept</i>, <i>concept</i>); #include "boost/concept_check.hpp"
BOOST_CLASS_REQUIRE3(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>namespace-of-concept</i>, <i>concept</i>);
BOOST_CLASS_REQUIRE4(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>type4</i>, <i>namespace-of-concept</i>, <i>concept</i>); template &lt;class T&gt;
struct Integer; // Is T a built-in integer type?
template &lt;class T&gt;
struct SignedInteger; // Is T a built-in signed integer type?
template &lt;class T&gt;
struct UnsignedInteger; // Is T a built-in unsigned integer type?
template &lt;class X, class Y&gt;
struct Convertible; // Is X convertible to Y?
template &lt;class T&gt;
struct <a href=
"../utility/Assignable.html">Assignable</a>; // Standard ref 23.1
template &lt;class T&gt;
struct SGI<a href=
"http://www.sgi.com/tech/stl/Assignable.html">Assignable</a>;
template &lt;class T&gt;
struct <a href=
"http://www.sgi.com/tech/stl/DefaultConstructible.html">DefaultConstructible</a>;
template &lt;class T&gt;
struct <a href=
"../utility/CopyConstructible.html">CopyConstructible</a>; // Standard ref 20.1.3
template &lt;class T&gt;
struct <a href=
"http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</a>; // Standard ref 20.1.1
template &lt;class T&gt;
struct <a href=
"../utility/LessThanComparable.html">LessThanComparable</a>; // Standard ref 20.1.2
template &lt;class T&gt;
struct Comparable; // The SGI STL <a href=
"http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</a> concept
</pre> </pre>
Deprecated macros: <h3><a name="iterator-concepts" id="iterator-concepts">Iterator Concept
Checking Classes</a></h3>
<pre>
template &lt;class Iter&gt;
struct <a href=
"http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a>; // Standard ref 24.1.1 Table 72
<pre> template &lt;class Iter, class T&gt;
// Apply concept checks in class definitions. struct <a href=
BOOST_CLASS_REQUIRES(<i>type</i>, <i>concept</i>); "http://www.sgi.com/tech/stl/OutputIterator.html">OutputIterator</a>; // Standard ref 24.1.2 Table 73
BOOST_CLASS_REQUIRES2(<i>type1</i>, <i>type2</i>, <i>concept</i>);
BOOST_CLASS_REQUIRES3(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>concept</i>); template &lt;class Iter&gt;
BOOST_CLASS_REQUIRES4(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>type4</i>, <i>concept</i>); struct <a href=
"http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>; // Standard ref 24.1.3 Table 74
template &lt;class Iter&gt;
struct Mutable_ForwardIterator;
template &lt;class Iter&gt;
struct <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>; // Standard ref 24.1.4 Table 75
template &lt;class Iter&gt;
struct Mutable_BidirectionalIterator;
template &lt;class Iter&gt;
struct <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a>; // Standard ref 24.1.5 Table 76
template &lt;class Iter&gt;
struct Mutable_RandomAccessIterator;
</pre> </pre>
<h3><a name="basic-concepts">Basic Concept Checking Classes</a></h3> <h3><a name="function-object-concepts" id=
"function-object-concepts">Function Object Concept Checking
Classes</a></h3>
<pre>
#include "boost/concept_check.hpp"
<pre> template &lt;class Func, class Return&gt;
template &lt;class T&gt; struct <a href="http://www.sgi.com/tech/stl/Generator.html">Generator</a>;
struct IntegerConcept; // Is T a built-in integer type?
template &lt;class T&gt; template &lt;class Func, class Return, class Arg&gt;
struct SignedIntegerConcept; // Is T a built-in signed integer type? struct <a href=
"http://www.sgi.com/tech/stl/UnaryFunction.html">UnaryFunction</a>;
template &lt;class T&gt; template &lt;class Func, class Return, class First, class Second&gt;
struct UnsignedIntegerConcept; // Is T a built-in unsigned integer type? struct <a href=
"http://www.sgi.com/tech/stl/BinaryFunction.html">BinaryFunction</a>;
template &lt;class X, class Y&gt; template &lt;class Func, class Arg&gt;
struct ConvertibleConcept; // Is X convertible to Y? struct Unary<a href=
"http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>;
template &lt;class T&gt; template &lt;class Func, class First, class Second&gt;
struct <a href="../utility/Assignable.html">Assignable</a>Concept; // Standard ref 23.1 struct <a href=
"http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>;
template &lt;class T&gt; template &lt;class Func, class First, class Second&gt;
struct SGI<a href="http://www.sgi.com/tech/stl/Assignable.html">Assignable</a>Concept; struct Const_BinaryPredicate;
template &lt;class T&gt; template &lt;class Func, class Return&gt;
struct <a struct <a href=
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">DefaultConstructible</a>Concept; "http://www.sgi.com/tech/stl/AdaptableGenerator.html">AdaptableGenerator</a>;
template &lt;class T&gt; template &lt;class Func, class Return, class Arg&gt;
struct <a href="../utility/CopyConstructible.html">CopyConstructible</a>Concept; // Standard ref 20.1.3 struct <a href=
"http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>;
template &lt;class T&gt; template &lt;class Func, class First, class Second&gt;
struct <a href="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</a>Concept; // Standard ref 20.1.1 struct <a href=
"http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html">AdaptableBinaryFunction</a>;
template &lt;class T&gt; template &lt;class Func, class Arg&gt;
struct <a href="../utility/LessThanComparable.html">LessThanComparable</a>Concept; // Standard ref 20.1.2 struct <a href=
"http://www.sgi.com/tech/stl/AdaptablePredicate.html">AdaptablePredicate</a>;
template &lt;class T&gt; template &lt;class Func, class First, class Second&gt;
struct ComparableConcept; // The SGI STL <a href="http://www.sgi.com/tech/stl/LessThanComparable.html">LessThanComparable</a> concept struct <a href=
"http://www.sgi.com/tech/stl/AdaptableBinaryPredicate.html">AdaptableBinaryPredicate</a>;
</pre> </pre>
<h3><a name="iterator-concepts">Iterator Concept Checking Classes</a></h3> <h3><a name="container-concepts" id="container-concepts">Container Concept
Checking Classes</a></h3>
<pre>
#include "boost/concept_check.hpp"
<pre> template &lt;class C&gt;
template &lt;class Iter&gt; struct <a href=
struct <a href="http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a>Concept; // Standard ref 24.1.1 Table 72 "http://www.sgi.com/tech/stl/Container.html">Container</a>; // Standard ref 23.1 Table 65
template &lt;class Iter, class T&gt; template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/OutputIterator.html">OutputIterator</a>Concept; // Standard ref 24.1.2 Table 73 struct Mutable_Container;
template &lt;class Iter&gt; template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>Concept; // Standard ref 24.1.3 Table 74 struct <a href=
"http://www.sgi.com/tech/stl/ForwardContainer.html">ForwardContainer</a>;
template &lt;class Iter&gt; template &lt;class C&gt;
struct Mutable_ForwardIteratorConcept; struct Mutable_ForwardContainer;
template &lt;class Iter&gt; template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>Concept; // Standard ref 24.1.4 Table 75 struct <a href=
"http://www.sgi.com/tech/stl/ReversibleContainer.html">ReversibleContainer</a>; // Standard ref 23.1 Table 66
template &lt;class Iter&gt; template &lt;class C&gt;
struct Mutable_BidirectionalIteratorConcept; struct Mutable_ReversibleContainer;
template &lt;class Iter&gt; template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">RandomAccessIterator</a>Concept; // Standard ref 24.1.5 Table 76 struct <a href=
"http://www.sgi.com/tech/stl/RandomAccessContainer.html">RandomAccessContainer</a>;
template &lt;class Iter&gt; template &lt;class C&gt;
struct Mutable_RandomAccessIteratorConcept; struct Mutable_RandomAccessContainer;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/Sequence.html">Sequence</a>; // Standard ref 23.1.1
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/FrontInsertionSequence.html">FrontInsertionSequence</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/BackInsertionSequence.html">BackInsertionSequence</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/AssociativeContainer.html">AssociativeContainer</a>; // Standard ref 23.1.2 Table 69
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html">UniqueAssociativeContainer</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/MultipleAssociativeContainer.html">MultipleAssociativeContainer</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/SimpleAssociativeContainer.html">SimpleAssociativeContainer</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/PairAssociativeContainer.html">PairAssociativeContainer</a>;
template &lt;class C&gt;
struct <a href=
"http://www.sgi.com/tech/stl/SortedAssociativeContainer.html">SortedAssociativeContainer</a>;
</pre> </pre>
<h3><a name="function-object-concepts">Function Object Concept Checking Classes</a></h3> <h3><a name="basic-archetype" id="basic-archetype">Basic Archetype
Classes</a></h3>
<pre>
#include "boost/concept_archetype.hpp"
<pre> template &lt;class T = int&gt;
template &lt;class Func, class Return&gt; class null_archetype; // A type that models no concepts.
struct <a href="http://www.sgi.com/tech/stl/Generator.html">Generator</a>Concept;
template &lt;class Func, class Return, class Arg&gt; template &lt;class Base = null_archetype&gt;
struct <a href="http://www.sgi.com/tech/stl/UnaryFunction.html">UnaryFunction</a>Concept; class default_constructible_archetype;
template &lt;class Func, class Return, class First, class Second&gt; template &lt;class Base = null_archetype&gt;
struct <a href="http://www.sgi.com/tech/stl/BinaryFunction.html">BinaryFunction</a>Concept; class assignable_archetype;
template &lt;class Func, class Arg&gt; template &lt;class Base = null_archetype&gt;
struct Unary<a href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>Concept; class copy_constructible_archetype;
template &lt;class Func, class First, class Second&gt; template &lt;class Base = null_archetype&gt;
struct <a href="http://www.sgi.com/tech/stl/BinaryPredicate.html">BinaryPredicate</a>Concept; class equality_comparable_archetype;
template &lt;class Func, class First, class Second&gt; template &lt;class T, class Base = null_archetype&gt;
struct Const_BinaryPredicateConcept; class convertible_to_archetype;
template &lt;class Func, class Return&gt;
struct <a href="http://www.sgi.com/tech/stl/AdaptableGenerator.html">AdaptableGenerator</a>Concept;
template &lt;class Func, class Return, class Arg&gt;
struct <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>Concept;
template &lt;class Func, class First, class Second&gt;
struct <a href="http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html">AdaptableBinaryFunction</a>Concept;
template &lt;class Func, class Arg&gt;
struct <a href="http://www.sgi.com/tech/stl/AdaptablePredicate.html">AdaptablePredicate</a>Concept;
template &lt;class Func, class First, class Second&gt;
struct <a href="http://www.sgi.com/tech/stl/AdaptableBinaryPredicate.html">AdaptableBinaryPredicate</a>Concept;
</pre> </pre>
<h3><a name="container-concepts">Container Concept Checking Classes</a></h3> <h3><a name="iterator-archetype" id="iterator-archetype">Iterator Archetype
Classes</a></h3>
<pre>
#include "boost/concept_archetype.hpp"
<pre> template &lt;class ValueType&gt;
template &lt;class C&gt; class trivial_iterator_archetype;
struct <a href="http://www.sgi.com/tech/stl/Container.html">Container</a>Concept; // Standard ref 23.1 Table 65
template &lt;class C&gt; template &lt;class ValueType&gt;
struct Mutable_ContainerConcept; class mutable_trivial_iterator_archetype;
template &lt;class C&gt; template &lt;class ValueType&gt;
struct <a href="http://www.sgi.com/tech/stl/ForwardContainer.html">ForwardContainer</a>Concept; class input_iterator_archetype;
template &lt;class C&gt; template &lt;class ValueType&gt;
struct Mutable_ForwardContainerConcept; class forward_iterator_archetype;
template &lt;class C&gt; template &lt;class ValueType&gt;
struct <a href="http://www.sgi.com/tech/stl/ReversibleContainer.html">ReversibleContainer</a>Concept; // Standard ref 23.1 Table 66 class bidirectional_iterator_archetype;
template &lt;class C&gt; template &lt;class ValueType&gt;
struct Mutable_ReversibleContainerConcept; class random_access_iterator_archetype;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/RandomAccessContainer.html">RandomAccessContainer</a>Concept;
template &lt;class C&gt;
struct Mutable_RandomAccessContainerConcept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/Sequence.html">Sequence</a>Concept; // Standard ref 23.1.1
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/FrontInsertionSequence.html">FrontInsertionSequence</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/BackInsertionSequence.html">BackInsertionSequence</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/AssociativeContainer.html">AssociativeContainer</a>Concept; // Standard ref 23.1.2 Table 69
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html">UniqueAssociativeContainer</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/MultipleAssociativeContainer.html">MultipleAssociativeContainer</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/SimpleAssociativeContainer.html">SimpleAssociativeContainer</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/PairAssociativeContainer.html">PairAssociativeContainer</a>Concept;
template &lt;class C&gt;
struct <a href="http://www.sgi.com/tech/stl/SortedAssociativeContainer.html">SortedAssociativeContainer</a>Concept;
</pre> </pre>
<h3><a name="function-object-archetype" id=
"function-object-archetype">Function Object Archetype Classes</a></h3>
<pre>
#include "boost/concept_archetype.hpp"
<h3><a name="basic-archetype">Basic Archetype Classes</a></h3> template &lt;class Arg, class Return&gt;
class unary_function_archetype;
<pre> template &lt;class Arg1, class Arg2, class Return&gt;
template &lt;class T = int&gt; class binary_function_archetype;
class null_archetype; // A type that models no concepts.
template &lt;class Base = null_archetype&gt; template &lt;class Arg&gt;
class default_constructible_archetype; class predicate_archetype;
template &lt;class Base = null_archetype&gt; template &lt;class Arg1, class Arg2&gt;
class assignable_archetype; class binary_predicate_archetype;
template &lt;class Base = null_archetype&gt;
class copy_constructible_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> </pre>
<h3><a name="iterator-archetype">Iterator Archetype Classes</a></h3> <h3><a name="container-archetype" id="container-archetype">Container
Archetype Classes</a></h3>
<pre> <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 UNDER CONSTRUCTION
</pre> </pre>
<p> <h3><a name="deprecated-functions" id="deprecated-functions">Deprecated
<a href="./concept_check.htm">Back to Introduction</a> Functions</a></h3>
<br> <pre>
<a href="./implementation.htm">Prev: Implementation</a> #include "boost/concept_check.hpp"
<br> template &lt;class Concept&gt;
<HR> void function_requires();
<TABLE> </pre>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY> <h3><a name="deprecated-macros" id="deprecated-macros">Deprecated
</HTML> Macros</a></h3>
<pre>
#include "boost/concept_check.hpp"
// Apply concept checks in class definitions.
BOOST_CLASS_REQUIRE(<i>type</i>, <i>namespace-of-concept</i>, <i>concept</i>);
BOOST_CLASS_REQUIRE2(<i>type1</i>, <i>type2</i>, <i>namespace-of-concept</i>, <i>concept</i>);
BOOST_CLASS_REQUIRE3(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>namespace-of-concept</i>, <i>concept</i>);
BOOST_CLASS_REQUIRE4(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>type4</i>, <i>namespace-of-concept</i>, <i>concept</i>);
// Apply concept checks in class definitions.
BOOST_CLASS_REQUIRES(<i>type</i>, <i>concept</i>);
BOOST_CLASS_REQUIRES2(<i>type1</i>, <i>type2</i>, <i>concept</i>);
BOOST_CLASS_REQUIRES3(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>concept</i>);
BOOST_CLASS_REQUIRES4(<i>type1</i>, <i>type2</i>, <i>type3</i>, <i>type4</i>, <i>concept</i>);
</pre>
<h3><a name="deprecated-concept-checking-classes" id=
"deprecated-concept-checking-classes">Deprecated Concept Checking
Classes</a></h3>
<p>For each of the concepts documented here, the library includes an
identical concept checking class whose name ends in
<code>Concept</code>” For example, in
addition to <code>RandomAccessIterator</code>, the library defines a
<code>RandomAccessIteratorConcept</code> class template.</p>
<p><a href="./concept_check.htm">Back to Introduction</a><br />
<a href="./implementation.htm">Prev: Implementation</a><br /></p>
<hr />
<table>
<tr valign="top">
<td nowrap="nowrap">Copyright &copy; 2000</td>
<td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
"mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>), 2007
<a href="mailto:dave@boost-consulting.com">David Abrahams</a>.</td>
</tr>
</table>
</body>
</html>

View File

@ -1,227 +1,186 @@
<HTML> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<!-- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-- 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>Using Concept Checks</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../boost.png"
ALT="C++ Boost" width="277" height="86">
<BR Clear> <html xmlns="http://www.w3.org/1999/xhtml">
<!-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000 -->
<!-- Distributed under the Boost -->
<!-- Software License, Version 1.0. (See accompanying -->
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
<head>
<meta name="generator" content=
"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<h2><a name="using-concept-checks">Using Concept Checks</a></h2> <title>Using Concept Checks</title>
<link rel="stylesheet" href="../../rst.css" type="text/css" />
</head>
For each concept there is a concept checking class which can be used <body bgcolor="#FFFFFF" link="#0000EE" text="#000000" vlink="#551A8B" alink=
to make sure that a given type (or set of types) models the concept. "#FF0000">
The Boost Concept Checking Library (BCCL) includes concept checking classes <img src="../../boost.png" alt="C++ Boost" width="277" height=
for all of the concepts used in the C++ standard library and a few "86" /><br clear="none" />
more. The <a href="./reference.htm">Reference</a> section lists these
concept checking classes. In addition, other boost libraries come with
concept checking classes for the concepts that are particular to those
libraries. For example, there are <a
href="../graph/doc/graph_concepts.html">graph concepts</a> and <a
href="../property_map/property_map.html">property map concepts</a>.
Also, whenever <b>anyone</b> writing a class of function template
needs to express requirements that are not yet stated by an existing
concept, a new concept checking class should be created. How
to do this is explained in <a href="./creating_concepts.htm">Creating
Concept Checking Classes</a>.
<p> <h2><a name="using-concept-checks" id="using-concept-checks">Using Concept
An example of a concept checking class from the BCCL is the Checks</a></h2>
<tt>EqualityComparableConcept</tt> class. The class corresponds to the
EqualityComparable requirements described in 20.1.1 of the C++
Standard, and to the <a
href="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</a>
concept documented in the SGI STL.
<pre> <p>For each concept there is a concept checking class template that can be
template &lt;class T&gt; used to make sure that a given type (or set of types) models the concept.
struct EqualityComparableConcept; The Boost Concept Checking Library (BCCL) includes concept checking class
templates for all of the concepts used in the C++ standard library and a
few more. See the <a href="./reference.htm">Reference</a> section for a
complete list. In addition, other boost libraries come with concept
checking classes for the concepts that are particular to those libraries.
For example, there are <a href="../graph/doc/graph_concepts.html">graph
concepts</a> and <a href="../property_map/property_map.html">property map
concepts</a>. Also, whenever <b>anyone</b> writing function templates needs
to express requirements that are not yet stated by an existing concept, a
new concept checking class should be created. How to do this is explained
in <a href="./creating_concepts.htm">Creating Concept Checking
Classes</a>.</p>
<p>An example of a concept checking class from the BCCL is the
<tt>EqualityComparableConcept</tt> class. The class corresponds to the
EqualityComparable requirements described in 20.1.1 of the C++ Standard,
and to the <a href=
"http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</a>
concept documented in the SGI STL.</p>
<pre>
template &lt;class T&gt;
struct EqualityComparable;
</pre> </pre>
The template argument <tt>T</tt> will the type to be checked. That is, <p>The template argument is the type to be checked. That is, the purpose of
the purpose of <tt>EqualityComparableConcept</tt> is to make sure that <tt>EqualityComparable&lt;<em>X</em>&gt;</tt> is to make sure that
the template argument given for <tt>T</tt> models the <tt><em>X</em></tt> models the EqualityComparable concept.</p>
EqualityComparable concept.
<p> <h4><tt>BOOST_CONCEPT_ASSERT()</tt></h4>
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 is EqualityComparable we need to
instantiate the concept checking class with the type and then find a
way to get the compiler to compile the <tt>constraints()</tt> function
without actually executing the function. The Boost Concept Checking
Library defines two utilities that make this easy:
<tt>function_requires()</tt> and <tt>BOOST_CLASS_REQUIRE</tt>.
<h4><tt>function_requires()</tt></h4> <p>The most versatile way of checking concept requirements is to use the
<code>BOOST_CONCEPT_ASSERT()</code> macro. You can use this macro at any
scope, by passing a concept checking template specialization enclosed in
parentheses. <strong>Note:</strong> that means invocations of
<code>BOOST_CONCEPT_ASSERT</code> will appear to use <strong>double
parentheses</strong>.</p>
<pre>
<font color="green">// In my library:</font>
template &lt;class T&gt;
void generic_library_function(T x)
{
BOOST_CONCEPT_ASSERT<strong>((</strong>EqualityComparable&lt;T&gt;<strong>))</strong>;
<font color="green">// ...</font>
};
The <tt>function_requires()</tt> function can be used in function bodies template &lt;class It&gt;
and the <tt>BOOST_CLASS_REQUIRE</tt> macro can be used inside class class generic_library_class
bodies. The <tt>function_requires()</tt> function takes no arguments, {
but has a template parameter for the concept checking class. This BOOST_CONCEPT_ASSERT<strong>((</strong>RandomAccessIterator&lt;It&gt;<strong>))</strong>;
means that the instantiated concept checking class must be given as an <font color="green">// ...</font>
explicit template argument, as shown below. };
<pre> <font color="green">// In the user's code:</font>
// In my library: class foo {
template &lt;class T&gt; <font color="green">//... </font>
void generic_library_function(T x) };
{
function_requires&lt; EqualityComparableConcept&lt;T&gt; &gt;();
// ...
};
// In the user's code: int main() {
class foo { foo x;
//... generic_library_function(x);
}; generic_library_class&lt;std::vector&lt;char&gt;::iterator&gt; y;
<font color="green">//...</font>
int main() { }
foo f;
generic_library_function(f);
return 0;
}
</pre> </pre>
<h4><tt>BOOST_CONCEPT_REQUIRES</tt></h4>
<h4><tt>BOOST_CLASS_REQUIRE</tt></h4> <p>One of the nice things about the proposed C++0x <a href=
"http://www.generic-programming.org/languages/conceptcpp/tutorial">syntax
for declaring concept constrained function templates</a> is the way that
constraints are part of the function <em>declaration</em>, so clients will
see them. <code>BOOST_CONCEPT_ASSERT</code> can only express constraints
within the function template definition, which hides the constraint in the
function body. Aside from the loss of a self-documenting interface,
asserting conformance only in the function body can undesirably delay
checking if the function is explicitly instantiated in a different
translation unit from the one in which it is called, or if the compiler
does link-time instantiation.</p>
The <tt>BOOST_CLASS_REQUIRE</tt> macro can be used inside a class <p>The <tt>BOOST_CONCEPT_REQUIRES</tt> macro can be used in a function
definition to check whether some type models a concept. Make sure template declaration to check whether some type models a concept. It
that the arguments to this macro are simply identifiers. You may need accepts two arguments, a <strong>list of constraints</strong>, and the
to use typedef to get your types into this form. function template's return type. The list of constraints takes the form of
a sequence of adjacent concept checking template specializations,
<pre> <strong>in double parentheses</strong>, and the function's return type must
// In my library: also be parenthesized. For example, the standard <code>stable_sort</code>
template &lt;class T&gt; algorithm might be declared as follows: class</p>
struct generic_library_class <pre>
{ template&lt;typename RanIter&gt;
BOOST_CLASS_REQUIRE(T, boost, EqualityComparableConcept); BOOST_CONCEPT_REQUIRES(
// ... ((Mutable_RandomAccessIterator&lt;RanIter&gt;))
}; ((LessThanComparable&lt;typename Mutable_RandomAccessIterator&lt;RanIter&gt;::value_type&gt;)),
(void)) <font color="green">// return type</font>
// In the user's code: stable_sort(RanIter,RanIter);
class foo {
//...
};
int main() {
generic_library_class&lt;foo&gt; glc;
// ...
return 0;
}
</pre> </pre>
<p>Note that the algorithm requires that the value type of the iterator be
LessThanComparable, and it accesses that value type through the
<code>Mutable_RandomAccessIterator</code> concept checking template. In
general, the Boost concept checking classes expose associated types as
nested member typedefs so that you can use this syntax, which mimics the
approach used in the concept support proposed for the next version of
C++.</p>
<h4>Example</h4> <h4>Multi-Type Concepts</h4>
<p> <p>Some concepts deal with more than one type. In this case the
Getting back to the earlier <a corresponding concept checking class will have multiple template
href="./concept_check.htm#motivating-example">motivating example</a>, parameters. The following example shows how <tt>BOOST_CONCEPT_REQUIRES</tt>
one good application of concept checks would be to insert is used with the <a href=
<tt>function_requires()</tt> at the top of <tt>std::stable_sort()</tt> "../property_map/ReadWritePropertyMap.html">ReadWritePropertyMap</a>
to make sure the template parameter type models <a concept, which takes two type parameters: a property map and the key type
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> for the map.</p>
RandomAccessIterator</a>. In addition, <tt>std::stable_sort()</tt> <pre>
requires that the <tt>value_type</tt> of the iterators be template &lt;class G, class Buffer, class BFSVisitor,
<a href="http://www.sgi.com/tech/stl/LessThanComparable.html"> class ColorMap&gt;
LessThanComparable</a>, so we also use <tt>function_requires()</tt> to BOOST_CONCEPT_REQUIRES(
check this. ((ReadWritePropertyMap&lt;ColorMap, typename IncidenceGraph&lt;G&gt;::vertex_descriptor&gt;)),
(void)) <font color="green">// return type</font>
<pre> breadth_first_search(G&amp; g,
template &lt;class RandomAccessIter&gt; typename graph_traits&lt;IncidenceGraph&gt;::vertex_descriptor s,
void stable_sort(RandomAccessIter first, RandomAccessIter last) Buffer&amp; Q, BFSVisitor vis, ColorMap color)
{ {
function_requires&lt; RandomAccessIteratorConcept&lt;RandomAccessIter&gt; &gt;(); typedef typename IncidenceGraph&lt;G&gt;::vertex_descriptor Vertex;
typedef typename std::iterator_traits&lt;RandomAccessIter&gt;::value_type value_type; ...
function_requires&lt; LessThanComparableConcept&lt;value_type&gt; &gt;(); }
...
}
</pre> </pre>
<p>Although concept checks are designed for use by generic library
implementors, they can also be useful to end users. Sometimes one may not
<!-- There are a few places where the SGI STL documentation differs be sure whether some type models a particular concept. The syntactic
from the corresponding requirements described in the C++ Standard. In requirements, at least, can easily be checked by creating a small program
these cases we use the definition from the C++ Standard. --> and using <tt>BOOST_CONCEPT_ASSERT</tt> with the type and concept in
question. For example:</p>
<p> <pre>
Some concepts deal with more than one type. In this case the <font color=
corresponding concept checking class will have multiple template "green">// Make sure list&lt;int&gt; has bidirectional iterators.</font>
parameters. The following example shows how BOOST_CONCEPT_ASSERT((BidirectionalIterator&lt;std::list&lt;int&gt;::iterator&gt;));
<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> </pre>
<p><a href="./concept_check.htm">Prev: Concept Checking
Introduction</a><br />
<a href="./creating_concepts.htm">Next: Creating Concept Checking
Classes</a><br /></p>
<hr />
As an example of using <tt>BOOST_CLASS_REQUIRE</tt> we look at a concept <table>
check that could be added to <tt>std::vector</tt>. One requirement <tr valign="top">
that is placed on the element type is that it must be <a <td nowrap="nowrap">Copyright &copy; 2000</td>
href="http://www.sgi.com/tech/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> <td><a href="../../people/jeremy_siek.htm">Jeremy Siek</a>(<a href=
namespace std { "mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>) Andrew
template &lt;class T&gt; Lumsdaine(<a href="mailto:lums@osl.iu.edu">lums@osl.iu.edu</a>), 2007
struct vector { <a href="mailto:dave@boost-consulting.com">David Abrahams</a>.</td>
BOOST_CLASS_REQUIRE(T, boost, AssignableConcept); </tr>
... </table>
}; </body>
} </html>
</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_check.cpp"><tt>stl_concept_checks.cpp</tt></a>
gives and example of applying the concept checks to STL containers.
<p>
<a href="./concept_check.htm">Prev: Concept Checking Introduction</a> <br>
<a href="./creating_concepts.htm">Next: Creating Concept Checking Classes</a>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF="../../people/jeremy_siek.htm">Jeremy Siek</A>(<A
HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
Andrew Lumsdaine</A>(<A HREF="mailto:lums@osl.iu.edu">lums@osl.iu.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>