|
|
|
@ -1,999 +0,0 @@
|
|
|
|
|
<HTML>
|
|
|
|
|
<!--
|
|
|
|
|
-- Copyright (c) Jeremy Siek and Andrew Lumsdaine 2000
|
|
|
|
|
--
|
|
|
|
|
-- Permission to use, copy, modify, distribute and sell this software
|
|
|
|
|
-- and its documentation for any purpose is hereby granted without fee,
|
|
|
|
|
-- provided that the above copyright notice appears in all copies and
|
|
|
|
|
-- that both that copyright notice and this permission notice appear
|
|
|
|
|
-- in supporting documentation. We make no
|
|
|
|
|
-- representations about the suitability of this software for any
|
|
|
|
|
-- purpose. It is provided "as is" without express or implied warranty.
|
|
|
|
|
-->
|
|
|
|
|
<Head>
|
|
|
|
|
<Title>Concept Checking</Title>
|
|
|
|
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
|
|
|
|
ALINK="#ff0000">
|
|
|
|
|
<IMG SRC="../../c++boost.gif"
|
|
|
|
|
ALT="C++ Boost" width="277" height="86">
|
|
|
|
|
|
|
|
|
|
<BR Clear>
|
|
|
|
|
|
|
|
|
|
<H1>
|
|
|
|
|
<A NAME="sec:concept-checking"></A>
|
|
|
|
|
header <a href="../../boost/pending/concept_checks.hpp">
|
|
|
|
|
<tt>boost/concept_checks.hpp</tt></a> and <a href="../../boost/pending/concept_archetypes.hpp">
|
|
|
|
|
<tt>boost/concept_archetypes.hpp</tt></a>
|
|
|
|
|
</H1>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Generic programming in C++ is characterized by the use of template
|
|
|
|
|
parameters to represent abstract data types (or ``concepts'').
|
|
|
|
|
However, the C++ language itself does not provide a mechanism for
|
|
|
|
|
explicitly handling concepts. As a result, it can be difficult to
|
|
|
|
|
insure that a concrete type meets the requirements of the concept it
|
|
|
|
|
is supposed to represent. Error messages resulting from incorrect use
|
|
|
|
|
of a concrete type can be particularly difficult to decipher. The
|
|
|
|
|
Boost Concept Checking Library provides mechanisms for checking
|
|
|
|
|
parameters in C++ template libraries. The mechanisms use standard C++
|
|
|
|
|
and introduce no run-time overhead. The main cost of using the
|
|
|
|
|
mechanism is in compile-time.
|
|
|
|
|
|
|
|
|
|
The documentation is organized into the following sections.
|
|
|
|
|
|
|
|
|
|
<OL>
|
|
|
|
|
<LI><a href="#introduction">Introduction</a></LI>
|
|
|
|
|
<LI><a href="#motivating-example">Motivating Example</a></LI>
|
|
|
|
|
<LI><a href="#using-concept-checks">Using Concept Checks</a></LI>
|
|
|
|
|
<LI><a href="#creating-concept-checks">Creating Concept Checking Classes</a></LI>
|
|
|
|
|
<LI><a href="#concept-covering">Concept Covering and Archetypes</a></LI>
|
|
|
|
|
<LI><a href="#programming-with-concepts">Programming With Concepts</a></LI>
|
|
|
|
|
<LI><a href="#implementation">Implementation</a></LI>
|
|
|
|
|
<LI><a href="#reference">Reference</a></LI>
|
|
|
|
|
<OL>
|
|
|
|
|
<LI><a href="#functions">Functions</a></LI>
|
|
|
|
|
<LI><a href="#classes">Classes</a></LI>
|
|
|
|
|
<LI><a href="#basic-concepts">Basic Concept Checking Classes</a></LI>
|
|
|
|
|
<LI><a href="#iterator-concepts">Iterator Concept Checking Classes</a></LI>
|
|
|
|
|
<LI><a href="#function-object-concepts">Function Object Concept Checking Classes</a></LI>
|
|
|
|
|
<LI><a href="#container-concepts">Container Concept Checking Classes</a></LI>
|
|
|
|
|
<LI><a href="#basic-archetype">Basic Archetype Classes</a></LI>
|
|
|
|
|
<LI><a href="#iterator-archetype">Iterator Archetype Classes</a></LI>
|
|
|
|
|
<LI><a href="#function-object-archetype">Function Object Archetype Classes</a></LI>
|
|
|
|
|
<LI><a href="#container-archetype">Container Archetype Classes</a></LI>
|
|
|
|
|
</OL>
|
|
|
|
|
<LI><a href="#history">History</a></LI>
|
|
|
|
|
<LI><a href="#publications">Publications</a></LI>
|
|
|
|
|
<LI><a href="#acknowledgements">Acknowledgements</a></LI>
|
|
|
|
|
</OL>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
|
|
|
|
contributed this library. X managed the formal review.
|
|
|
|
|
|
|
|
|
|
<h2><a name="introduction">Introduction</a></h2>
|
|
|
|
|
|
|
|
|
|
A <i>concept</i> is a set of requirements (valid expressions,
|
|
|
|
|
associated types, semantic invariants, complexity guarantees, etc.)
|
|
|
|
|
that a type must fulfill to be correctly used as arguments in a call
|
|
|
|
|
to a generic algorithm. In C++, concepts are represented by formal
|
|
|
|
|
template parameters to function templates (generic algorithms).
|
|
|
|
|
However, C++ has no explicit mechanism for representing concepts ---
|
|
|
|
|
template parameters are merely placeholders. By convention, these
|
|
|
|
|
parameters are given names corresponding to the concept that is
|
|
|
|
|
required, but a C++ compiler does not enforce compliance to the
|
|
|
|
|
concept when the template parameter is bound to an actual type.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Naturally, if a generic algorithm is invoked with a type that does not
|
|
|
|
|
fulfill at least the syntactic requirements of the concept, a
|
|
|
|
|
compile-time error will occur. However, this error will not <i>per
|
|
|
|
|
se</i> reflect the fact that the type did not meet all of the
|
|
|
|
|
requirements of the concept. Rather, the error may occur deep inside
|
|
|
|
|
the instantiation hierarchy at the point where an expression is not
|
|
|
|
|
valid for the type, or where a presumed associated type is not
|
|
|
|
|
available. The resulting error messages are largely uninformative and
|
|
|
|
|
basically impenetrable.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
What is required is a mechanism for enforcing ``concept safety'' at
|
|
|
|
|
(or close to) the point of instantiation. The Boost Concept Checking
|
|
|
|
|
Library uses some standard C++ constructs to enforce early concept
|
|
|
|
|
compliance and that provides more informative error messages upon
|
|
|
|
|
non-compliance.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Note that this technique only addresses the syntactic
|
|
|
|
|
requirements of concepts (the valid expressions and associated types).
|
|
|
|
|
We do not address the semantic invariants or complexity guarantees,
|
|
|
|
|
which are also part of concept requirements..
|
|
|
|
|
|
|
|
|
|
<h2><a name="motivating-example">Motivating Example</a></h2>
|
|
|
|
|
|
|
|
|
|
We present a simple example to illustrate incorrect usage of a
|
|
|
|
|
template library and the resulting error messages. In the code below,
|
|
|
|
|
the generic <tt>std::stable_sort()</tt> algorithm from the Standard
|
|
|
|
|
Template Library (STL)[<a
|
|
|
|
|
href="bibliography.html#austern99:_gener_progr_stl">3</a>, <a
|
|
|
|
|
href="bibliography.html#IB-H965502">4</a>,<a
|
|
|
|
|
href="bibliography.html#stepa.lee-1994:the.s:TR">5</a>] is applied to
|
|
|
|
|
a linked list.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
<a href="./bad_error_eg.cpp">bad_error_eg.cpp</a>:
|
|
|
|
|
1 #include <list>
|
|
|
|
|
2 #include <algorithm>
|
|
|
|
|
3
|
|
|
|
|
4 struct foo {
|
|
|
|
|
5 bool operator<(const foo&) const { return false; }
|
|
|
|
|
6 };
|
|
|
|
|
7 int main(int, char*[]) {
|
|
|
|
|
8 std::list<foo> v;
|
|
|
|
|
9 std::stable_sort(v.begin(), v.end());
|
|
|
|
|
10 return 0;
|
|
|
|
|
11 }
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
Here, the
|
|
|
|
|
<tt>std::stable_sort()</tt> algorithm is prototyped as follows:
|
|
|
|
|
<pre>
|
|
|
|
|
template <class RandomAccessIterator>
|
|
|
|
|
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
Attempting to compile this code with Gnu C++ produces the following
|
|
|
|
|
compiler error. The output from other compilers is listed in the
|
|
|
|
|
Appendix.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
stl_algo.h: In function `void __merge_sort_loop<_List_iterator
|
|
|
|
|
<foo,foo &,foo *>, foo *, int>(_List_iterator<foo,foo &,foo *>,
|
|
|
|
|
_List_iterator<foo,foo &,foo *>, foo *, int)':
|
|
|
|
|
stl_algo.h:1448: instantiated from `__merge_sort_with_buffer
|
|
|
|
|
<_List_iterator<foo,foo &,foo *>, foo *, int>(
|
|
|
|
|
_List_iterator<foo,foo &,foo *>, _List_iterator<foo,foo &,foo *>,
|
|
|
|
|
foo *, int *)'
|
|
|
|
|
stl_algo.h:1485: instantiated from `__stable_sort_adaptive<
|
|
|
|
|
_List_iterator<foo,foo &,foo *>, foo *, int>(_List_iterator
|
|
|
|
|
<foo,foo &,foo *>, _List_iterator<foo,foo &,foo *>, foo *, int)'
|
|
|
|
|
stl_algo.h:1524: instantiated from here
|
|
|
|
|
stl_algo.h:1377: no match for `_List_iterator<foo,foo &,foo *> & -
|
|
|
|
|
_List_iterator<foo,foo &,foo *> &'
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
In this case, the fundamental error is that
|
|
|
|
|
<tt>std:list::iterator</tt> does not model the concept of <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a>. The list iterator is only bidirectional, not
|
|
|
|
|
fully random access (as would be a vector iterator). Unfortunately,
|
|
|
|
|
there is nothing in the error message to indicate this to the user.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
To a C++ programmer having enough experience with template libraries
|
|
|
|
|
the error may be obvious. However, for the uninitiated, there are several
|
|
|
|
|
reasons why this message would be hard to understand.
|
|
|
|
|
|
|
|
|
|
<OL>
|
|
|
|
|
<LI> The location of the error, line 9 of <tt>bad_error_eg.cpp</tt>
|
|
|
|
|
is not pointed to by the error message, despite the fact that Gnu C++
|
|
|
|
|
prints up to 4 levels deep in the instantiation stack.
|
|
|
|
|
<LI> There is no textual correlation between the error message and the
|
|
|
|
|
documented requirements for <tt>std::stable_sort()</tt> and for
|
|
|
|
|
<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a>.
|
|
|
|
|
<LI> The error message is overly long, listing functions internal
|
|
|
|
|
to the STL that the user does not (and should not!) know or care
|
|
|
|
|
about.
|
|
|
|
|
<LI> With so many internal library functions listed in the error
|
|
|
|
|
message, the programmer could easily infer that the error is due
|
|
|
|
|
to the library, rather than to his or her own code.
|
|
|
|
|
</OL>
|
|
|
|
|
|
|
|
|
|
The following is an example of what we might expect from a more
|
|
|
|
|
informative message (and is in fact what the Boost Concept Checking
|
|
|
|
|
Library produces):
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
concept_checks.hpp: In method `void LessThanComparable_concept
|
|
|
|
|
<_List_iterator<foo,foo &,foo *> >::constraints()':
|
|
|
|
|
concept_checks.hpp:334: instantiated from `RandomAccessIterator_concept
|
|
|
|
|
<_List_iterator<foo,foo &,foo *> >::constraints()'
|
|
|
|
|
bad_error_eg.cpp:9: instantiated from `stable_sort<_List_iterator
|
|
|
|
|
<foo,foo &,foo *> >(_List_iterator<foo,foo &,foo *>,
|
|
|
|
|
_List_iterator<foo,foo &,foo *>)'
|
|
|
|
|
concept_checks.hpp:209: no match for `_List_iterator<foo,foo &,foo *> &
|
|
|
|
|
< _List_iterator<foo,foo &,foo *> &'
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
This message rectifies several of the shortcomings of the standard
|
|
|
|
|
error messages.
|
|
|
|
|
|
|
|
|
|
<UL>
|
|
|
|
|
<LI> The location of the error, <tt>bad_error_eg.cpp:9</tt> is
|
|
|
|
|
specified in the error message.
|
|
|
|
|
<LI> The message refers explicitly to concepts that the user can look
|
|
|
|
|
up in the STL documentation (<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a>).
|
|
|
|
|
<LI> The error message is now much shorter and does not reveal
|
|
|
|
|
internal STL functions.
|
|
|
|
|
<LI> The presence of <tt>concept_checks.hpp</tt> and
|
|
|
|
|
<tt>constraints()</tt> in the error message alerts the user to the
|
|
|
|
|
fact that the error lies in the user code and not in the library
|
|
|
|
|
implementation.
|
|
|
|
|
</UL>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="using-concept-checks">Using Concept Checks</a></h2>
|
|
|
|
|
|
|
|
|
|
For each concept there is a concept checking class which can be used
|
|
|
|
|
to make sure that a given type (or set of types) models the concept.
|
|
|
|
|
The Boost Concept Checking Library includes concept checking classes
|
|
|
|
|
for all of the concepts used in the C++ standard library and a few
|
|
|
|
|
more. The <a href="#reference">Reference</a> section below lists these
|
|
|
|
|
concept checking classes. In addition, other boost libraries come with
|
|
|
|
|
concept checking classes for the concepts that are particular to those
|
|
|
|
|
libraries. An example of one of these classes is the
|
|
|
|
|
<tt>EqualityComparableConcept</tt> class.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class T> struct EqualityComparableConcept;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
Each concept checking class has a member function named
|
|
|
|
|
<tt>constraints()</tt> which contains the valid expressions for the
|
|
|
|
|
concept. To check whether some type, say <tt>foo</tt>, is
|
|
|
|
|
EqualityComparable, we need to instantiate the concept checking class
|
|
|
|
|
with foo: <tt>EqualityComparableConcept<foo></tt> and then find
|
|
|
|
|
a way to get the compiler to compile the <tt>constraints()</tt>
|
|
|
|
|
function without actually calling it. The Boost Concept Checking
|
|
|
|
|
Library defines two utilities that make this easy:
|
|
|
|
|
<tt>function_requires()</tt> and <tt>BOOST_CLASS_REQUIRES</tt>.
|
|
|
|
|
<tt>function_requires()</tt> function can be used in function bodies
|
|
|
|
|
and the <tt>BOOST_CLASS_REQUIRES</tt> macro can be used inside class
|
|
|
|
|
bodies. The <tt>function_requires()</tt> function takes no arguments,
|
|
|
|
|
but has a template parameter for the concept checking class. This
|
|
|
|
|
means that the instantiated concept checking class must be given as an
|
|
|
|
|
explicit template argument, as shown below.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
void some_function_using_foo() {
|
|
|
|
|
function_requires< EqualityComparableConcept<foo> >();
|
|
|
|
|
// ...
|
|
|
|
|
};
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
The <tt>BOOST_CLASS_REQUIRES</tt> macro can be used inside a class
|
|
|
|
|
definition to check whether some type models a concept.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
struct some_class_using_foo {
|
|
|
|
|
BOOST_CLASS_REQUIRES(foo, EqualityComparableConcept);
|
|
|
|
|
};
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
To add concept checks to the <tt>std::stable_sort()</tt> function the
|
|
|
|
|
library implementor would simply insert <tt>function_requires()</tt>
|
|
|
|
|
at the top of <tt>std::stable_sort()</tt> to make sure the template
|
|
|
|
|
parameter type models <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a>. In addition, <tt>std::stable_sort()</tt>
|
|
|
|
|
requires that the <tt>value_type</tt> of the iterators be
|
|
|
|
|
<a href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a>, so we also use <tt>function_requires()</tt> to
|
|
|
|
|
check this.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class RandomAccessIter>
|
|
|
|
|
void stable_sort(RandomAccessIter first, RandomAccessIter last)
|
|
|
|
|
{
|
|
|
|
|
function_requires< RandomAccessIteratorConcept<RandomAccessIter> >();
|
|
|
|
|
typedef typename std::iterator_traits<RandomAccessIter>::value_type value_type;
|
|
|
|
|
function_requires< LessThanComparableConcept<value_type> >();
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- There are a few places where the SGI STL documentation differs
|
|
|
|
|
from the corresponding requirements described in the C++ Standard. In
|
|
|
|
|
these cases we use the definition from the C++ Standard. -->
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Some concepts deal with more than one type. In this case the
|
|
|
|
|
corresponding concept checking class will have multiple template
|
|
|
|
|
parameters. The following example shows how
|
|
|
|
|
<tt>function_requires()</tt> is used with the <a
|
|
|
|
|
href="../property_map/ReadWritePropertyMap.html">ReadWritePropertyMap</a>
|
|
|
|
|
concept which takes two type parameters: a property map and the key
|
|
|
|
|
type for the map.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class IncidenceGraph, class Buffer, class BFSVisitor,
|
|
|
|
|
class ColorMap>
|
|
|
|
|
void breadth_first_search(IncidenceGraph& g,
|
|
|
|
|
typename graph_traits<IncidenceGraph>::vertex_descriptor s,
|
|
|
|
|
Buffer& Q, BFSVisitor vis, ColorMap color)
|
|
|
|
|
{
|
|
|
|
|
typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
|
|
|
|
|
function_requires< ReadWritePropertyMap<ColorMap, Vertex> >();
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
As an example of using <tt>class_requires</tt> we look at a concept
|
|
|
|
|
check that could be added to <tt>std::vector</tt>. One requirement
|
|
|
|
|
that is placed on the element type is that it must be <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</a>.
|
|
|
|
|
We can check this by inserting
|
|
|
|
|
<tt>class_requires<AssignableConcept<T> ></tt> at the top
|
|
|
|
|
of the definition for <tt>std::vector</tt>.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
namespace std {
|
|
|
|
|
template <class T>
|
|
|
|
|
struct vector {
|
|
|
|
|
typedef typename class_requires< AssignableConcept<T> >::check req;
|
|
|
|
|
...
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Although the concept checks are designed for use by generic library
|
|
|
|
|
implementors, they can also be useful to end users. Sometimes one may
|
|
|
|
|
not be sure whether some type models a particular concept. This can
|
|
|
|
|
easily be checked by creating a small program and using
|
|
|
|
|
<tt>function_requires()</tt> with the type and concept in question.
|
|
|
|
|
The file <a
|
|
|
|
|
href="./stl_concept_checks.cpp"><tt>stl_concept_checks.cpp</tt></a>
|
|
|
|
|
gives and example of applying the concept checks to STL
|
|
|
|
|
containers. The file is listed here:
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
#include <boost/concept_checks.hpp>
|
|
|
|
|
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <list>
|
|
|
|
|
#include <deque>
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main()
|
|
|
|
|
{
|
|
|
|
|
typedef std::vector<int> Vector;
|
|
|
|
|
typedef std::deque<int> Deque;
|
|
|
|
|
typedef std::list<int> List;
|
|
|
|
|
|
|
|
|
|
function_requires< Mutable_RandomAccessContainer<Vector> >();
|
|
|
|
|
function_requires< BackInsertionSequence<Vector> >();
|
|
|
|
|
|
|
|
|
|
function_requires< Mutable_RandomAccessContainer<Deque> >();
|
|
|
|
|
function_requires< FrontInsertionSequence<Deque> >();
|
|
|
|
|
function_requires< BackInsertionSequence<Deque> >();
|
|
|
|
|
|
|
|
|
|
function_requires< Mutable_ReversibleContainer<List> >();
|
|
|
|
|
function_requires< FrontInsertionSequence<List> >();
|
|
|
|
|
function_requires< BackInsertionSequence<List> >();
|
|
|
|
|
|
|
|
|
|
typedef std::set<int> Set;
|
|
|
|
|
typedef std::multiset<int> MultiSet;
|
|
|
|
|
typedef std::map<int,int> Map;
|
|
|
|
|
typedef std::multimap<int,int> MultiMap;
|
|
|
|
|
|
|
|
|
|
function_requires< SortedAssociativeContainer<Set> >();
|
|
|
|
|
function_requires< SimpleAssociativeContainer<Set> >();
|
|
|
|
|
function_requires< UniqueAssociativeContainer<Set> >();
|
|
|
|
|
|
|
|
|
|
function_requires< SortedAssociativeContainer<MultiSet> >();
|
|
|
|
|
function_requires< SimpleAssociativeContainer<MultiSet> >();
|
|
|
|
|
function_requires< MultipleAssociativeContainer<MultiSet> >();
|
|
|
|
|
|
|
|
|
|
function_requires< SortedAssociativeContainer<Map> >();
|
|
|
|
|
function_requires< UniqueAssociativeContainer<Map> >();
|
|
|
|
|
function_requires< PairAssociativeContainer<Map> >();
|
|
|
|
|
|
|
|
|
|
function_requires< SortedAssociativeContainer<MultiMap> >();
|
|
|
|
|
function_requires< MultipleAssociativeContainer<MultiMap> >();
|
|
|
|
|
function_requires< PairAssociativeContainer<MultiMap> >();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="creating-concept-checks">Creating Concept Checking Classes</a></h2>
|
|
|
|
|
|
|
|
|
|
As an example of how to create a concept checking class, we look
|
|
|
|
|
at how to create the corresponding checks for the
|
|
|
|
|
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a> concept. First, as a convention we name the
|
|
|
|
|
concept checking class after the concept, and add the suffix
|
|
|
|
|
``<tt>_concept</tt>''. Note that the <tt>REQUIRE</tt> macro expects
|
|
|
|
|
the suffix to be there. Next we must define a member function named
|
|
|
|
|
<tt>constraints()</tt> in which we will exercise the valid expressions
|
|
|
|
|
of the concept. The <tt>REQUIRE</tt> macro expects this function's
|
|
|
|
|
signature to appear exactly as it is appears below: a <tt>void</tt>
|
|
|
|
|
non-const member function with no parameters.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
The first part of the <tt>constraints()</tt> function includes
|
|
|
|
|
the requirements that correspond to the <i>refinement</i> relationship
|
|
|
|
|
between <a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a> and the concepts which it builds upon:
|
|
|
|
|
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
|
|
|
|
|
BidirectionalIterator</a> and
|
|
|
|
|
<a href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a>. We could have instead used
|
|
|
|
|
<tt>CLASS_REQUIRES</tt> and placed these requirements in the class
|
|
|
|
|
body, however <tt>CLASS_REQUIRES</tt> uses C++ language features that
|
|
|
|
|
are less portable.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Next we check that the <tt>iterator_category</tt> of the iterator is
|
|
|
|
|
either <tt>std::random_access_iterator_tag</tt> or a derived class.
|
|
|
|
|
After that we write out some code that corresponds to the valid
|
|
|
|
|
expressions of the <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a> concept. Typedefs can also be added to
|
|
|
|
|
enforce the associated types of the concept.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Iter>
|
|
|
|
|
struct RandomAccessIterator_concept
|
|
|
|
|
{
|
|
|
|
|
void constraints() {
|
|
|
|
|
function_requires< BidirectionalIteratorConcept<Iter> >();
|
|
|
|
|
function_requires< LessThanComparableConcept<Iter> >();
|
|
|
|
|
function_requires< ConvertibleConcept<
|
|
|
|
|
typename std::iterator_traits<Iter>::iterator_category,
|
|
|
|
|
std::random_access_iterator_tag> >();
|
|
|
|
|
|
|
|
|
|
i += n;
|
|
|
|
|
i = i + n; i = n + i;
|
|
|
|
|
i -= n;
|
|
|
|
|
i = i - n;
|
|
|
|
|
n = i - j;
|
|
|
|
|
i[n];
|
|
|
|
|
}
|
|
|
|
|
Iter a, b;
|
|
|
|
|
Iter i, j;
|
|
|
|
|
typename std::iterator_traits<Iter>::difference_type n;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
One potential pitfall in designing concept checking classes is using
|
|
|
|
|
more expressions in the constraint function than necessary. For
|
|
|
|
|
example, it is easy to accidentally use the default constructor to
|
|
|
|
|
create the objects that will be needed in the expressions (and not all
|
|
|
|
|
concepts require a default constructor). This is the reason we write
|
|
|
|
|
the constraint function as a member function of a class. The objects
|
|
|
|
|
involved in the expressions are declared as data members of the class.
|
|
|
|
|
Since objects of the constraints class template are never
|
|
|
|
|
instantiated, the default constructor for the concept checking class
|
|
|
|
|
is never instantiated. Hence the data member's default constructors
|
|
|
|
|
are never instantiated (C++ Standard Section 14.7.1 9).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="concept-covering">Concept Covering and Archetypes</a></h2>
|
|
|
|
|
|
|
|
|
|
We have discussed how it is important to select the minimal
|
|
|
|
|
requirements (concepts) for the inputs to a component, but it is
|
|
|
|
|
equally important to verify that the chosen concepts <i>cover</i> the
|
|
|
|
|
algorithm. That is, any possible user error should be caught by the
|
|
|
|
|
concept checks and not let slip through. Concept coverage can be
|
|
|
|
|
verified through the use of <i>archetype classes</i>. An archetype
|
|
|
|
|
class is an exact implementation of the interface associated with a
|
|
|
|
|
particular concept. The run-time behavior of the archetype class is
|
|
|
|
|
not important, the functions can be left empty. A simple test program
|
|
|
|
|
can then be compiled with the archetype classes as the inputs to the
|
|
|
|
|
component. If the program compiles then one can be sure that the
|
|
|
|
|
concepts cover the component.
|
|
|
|
|
|
|
|
|
|
The following code shows the archetype class for the <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/trivial.html">TrivialIterator</a>
|
|
|
|
|
concept. Some care must be taken to ensure that the archetype is an
|
|
|
|
|
exact match to the concept. For example, the concept states that the
|
|
|
|
|
return type of <tt>operator*()</tt> must be convertible to the value
|
|
|
|
|
type. It does not state the more stringent requirement that the return
|
|
|
|
|
type be <tt>T&</tt> or <tt>const T&</tt>. That means it would be a
|
|
|
|
|
mistake to use <tt>T&</tt> or <tt>const T&</tt> for the return type
|
|
|
|
|
of the archetype class. The correct approach is to create an
|
|
|
|
|
artificial return type that is convertible to <tt>T</tt>, as we have
|
|
|
|
|
done here with <tt>input_proxy</tt>. The validity of the archetype
|
|
|
|
|
class test is completely dependent on it being an exact match with the
|
|
|
|
|
concept, which must be verified by careful (manual) inspection.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class T>
|
|
|
|
|
struct input_proxy {
|
|
|
|
|
operator T() { return t; }
|
|
|
|
|
static T t;
|
|
|
|
|
};
|
|
|
|
|
template <class T>
|
|
|
|
|
class trivial_iterator_archetype
|
|
|
|
|
{
|
|
|
|
|
typedef trivial_iterator_archetype self;
|
|
|
|
|
public:
|
|
|
|
|
trivial_iterator_archetype() { }
|
|
|
|
|
trivial_iterator_archetype(const self&) { }
|
|
|
|
|
self& operator=(const self&) { return *this; }
|
|
|
|
|
friend bool operator==(const self&, const self&) { return true; }
|
|
|
|
|
friend bool operator!=(const self&, const self&) { return true; }
|
|
|
|
|
input_proxy<T> operator*() { return input_proxy<T>(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace std {
|
|
|
|
|
template <class T>
|
|
|
|
|
struct iterator_traits< trivial_iterator_archetype<T> >
|
|
|
|
|
{
|
|
|
|
|
typedef T value_type;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
Generic algorithms are often tested by being instantiated with a
|
|
|
|
|
number of common input types. For example, one might apply
|
|
|
|
|
<tt>std::stable_sort()</tt> with basic pointer types as the iterators.
|
|
|
|
|
Though appropriate for testing the run-time behavior of the algorithm,
|
|
|
|
|
this is not helpful for ensuring concept coverage because C++ types
|
|
|
|
|
never match particular concepts, they often provide much more than the
|
|
|
|
|
minimal functionality required by any one concept. That is, even
|
|
|
|
|
though the function template compiles with a given type, the concept
|
|
|
|
|
requirements may still fall short of covering the functions actual
|
|
|
|
|
requirements. This is why it is important to compile with archetype
|
|
|
|
|
classes in addition to testing with common input types.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
The following is an excerpt from <a
|
|
|
|
|
href="./stl_concept_covering.cpp"><tt>stl_concept_covering.cpp</tt></a>
|
|
|
|
|
that shows how archetypes can be used to check the requirement
|
|
|
|
|
documentation for
|
|
|
|
|
<a href="http://www.sgi.com/Technology/STL/stable_sort.html">
|
|
|
|
|
<tt>std::stable_sort()</tt></a>. In this case, it looks like the <a
|
|
|
|
|
href="../utility/CopyConstructible.html">CopyConstructible</a> and <a
|
|
|
|
|
href="../utility/Assignable.html">Assignable</a> requirements were
|
|
|
|
|
forgotten in the SGI STL documentation (try removing those
|
|
|
|
|
archetypes). The Boost archetype classes have been designed so that
|
|
|
|
|
they can be layered. In this example the value type of the iterator
|
|
|
|
|
is composed out of three archetypes. In the archetype class reference
|
|
|
|
|
below, template parameters named <tt>Base</tt> indicate where the
|
|
|
|
|
layered archetype can be used.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
{
|
|
|
|
|
typedef less_than_comparable_archetype<
|
|
|
|
|
copy_constructible_archetype<
|
|
|
|
|
assignable_archetype<> > > ValueType;
|
|
|
|
|
random_access_iterator_archetype<ValueType> ri;
|
|
|
|
|
std::stable_sort(ri, ri);
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="programming-with-concepts">Programming with Concepts</a></h2>
|
|
|
|
|
|
|
|
|
|
The process of deciding how to group requirements into concepts and
|
|
|
|
|
deciding which concepts to use in each algorithm is perhaps the most
|
|
|
|
|
difficult (yet most important) part of building a generic library.
|
|
|
|
|
A guiding principle to use during this process is one we
|
|
|
|
|
call the <i>requirement minimization principle</i>.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
<b>Requirement Minimization Principle:</b> Minimize the requirements
|
|
|
|
|
on the input parameters of a component to increase its reusability.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
There is natural tension in this statement. By definition, the input
|
|
|
|
|
parameters must be used by the component in order for the component to
|
|
|
|
|
accomplish its task (by ``component'' we mean a function or class
|
|
|
|
|
template). The challenge then is to implement the component in such a
|
|
|
|
|
way that makes the fewest assumptions (the minimum requirements) about
|
|
|
|
|
the inputs while still accomplishing the task.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
The traditional notions of <i>abstraction</i> tie in directly to the
|
|
|
|
|
idea of minimal requirements. The more abstract the input, the fewer
|
|
|
|
|
the requirements. Thus, concepts are simply the embodiment of generic
|
|
|
|
|
abstract data types in C++ template programming.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
When designing the concepts for some problem domain it is important to
|
|
|
|
|
keep in mind their purpose, namely to express the requirements for the
|
|
|
|
|
input to the components. With respect to the requirement minimization
|
|
|
|
|
principle, this means we want to minimize concepts.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
It is important to note, however, that
|
|
|
|
|
minimizing concepts does not mean simply
|
|
|
|
|
reducing the number of valid expressions
|
|
|
|
|
in the concept.
|
|
|
|
|
For example, the
|
|
|
|
|
<tt>std::stable_sort()</tt> function requires that the value type of
|
|
|
|
|
the iterator be <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a>, which not only
|
|
|
|
|
includes <tt>operator<()</tt>, but also <tt>operator>()</tt>,
|
|
|
|
|
<tt>operator<=()</tt>, and <tt>operator>=()</tt>.
|
|
|
|
|
It turns out that <tt>std::stable_sort()</tt> only uses
|
|
|
|
|
<tt>operator<()</tt>. The question then arises: should
|
|
|
|
|
<tt>std::stable_sort()</tt> be specified in terms of the concept
|
|
|
|
|
<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a> or in terms of a concept that only
|
|
|
|
|
requires <tt>operator<()</tt>?
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
We remark first that the use of <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a> does not really violate the requirement
|
|
|
|
|
minimization principle because all of the other operators can be
|
|
|
|
|
trivially implemented in terms of <tt>operator<()</tt>. By
|
|
|
|
|
``trivial'' we mean one line of code and a constant run-time cost.
|
|
|
|
|
More fundamentally, however, the use of <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a> does not violate the requirement minimization
|
|
|
|
|
principle because all of the comparison operators (<tt><</tt>,
|
|
|
|
|
<tt>></tt>, <tt><=</tt>, <tt>>=</tt>) are conceptually equivalent (in
|
|
|
|
|
a mathematical sense). Adding conceptually equivalent valid
|
|
|
|
|
expressions is not a violation of the requirement minimization
|
|
|
|
|
principle because no new semantics are being added --- only new
|
|
|
|
|
syntax. The added syntax increases re-usability.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
For example,
|
|
|
|
|
the
|
|
|
|
|
maintainer of the <tt>std::stable_sort()</tt> may some day change the
|
|
|
|
|
implementation in places to use <tt>operator>()</tt> instead of
|
|
|
|
|
<tt>operator<()</tt>, since, after all, they are equivalent. Since the
|
|
|
|
|
requirements are part of the public interface, such a change could
|
|
|
|
|
potentially break client code. If instead
|
|
|
|
|
<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/LessThanComparable.html">
|
|
|
|
|
LessThanComparable</a> is given as the requirement for
|
|
|
|
|
<tt>std::stable_sort()</tt>, then the maintainer is given a reasonable
|
|
|
|
|
amount of flexibility within which to work.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Minimality in concepts is a property associated with the underlying
|
|
|
|
|
semantics of the problem domain being represented. In the problem
|
|
|
|
|
domain of basic containers, requiring traversal in a single direction
|
|
|
|
|
is a smaller requirement than requiring traversal in both directions
|
|
|
|
|
(hence the distinction between <a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/ForwardIterator.html">
|
|
|
|
|
ForwardIterator</a> and
|
|
|
|
|
<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
|
|
|
|
|
BidirectionalIterator</a>). The semantic difference can be easily seen
|
|
|
|
|
in the difference between the set of concrete data structures that
|
|
|
|
|
have forward iterators versus the set that has bidirectional
|
|
|
|
|
iterators. For example, singly-linked lists would fall in the set of
|
|
|
|
|
data structures having forward iterators, but not bidirectional
|
|
|
|
|
iterators. In addition, the set of algorithms that one can implement
|
|
|
|
|
using only forward iterators is quite different than the set that can
|
|
|
|
|
be implemented with bidirectional iterators. Because of this, it is
|
|
|
|
|
important to factor families of requirements into rather fine-grained
|
|
|
|
|
concepts. For example, the requirements for iterators are factored
|
|
|
|
|
into the six STL iterator concepts (trivial, output, input, forward,
|
|
|
|
|
bidirectional, and random access).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="implementation">Implementation</a></h2>
|
|
|
|
|
|
|
|
|
|
Ideally we would like to catch, and indicate, the concept violation at
|
|
|
|
|
the point of instantiation. As mentioned in D&E[<a
|
|
|
|
|
href="bibliography.html#stroustrup94:_design_evolution">2</a>], the error
|
|
|
|
|
can be caught by exercising all of the requirements needed by the
|
|
|
|
|
function template. Exactly how the requirements (the valid
|
|
|
|
|
expressions in particular) are exercised is a tricky issue, since we
|
|
|
|
|
want the code to be compiled --- <i>but not executed</i>. Our
|
|
|
|
|
approach is to exercise the requirements in a separate function that
|
|
|
|
|
is assigned to a function pointer. In this case, the compiler will
|
|
|
|
|
instantiate the function but will not actually invoke it. In
|
|
|
|
|
addition, an optimizing compiler will remove the pointer assignment as
|
|
|
|
|
``dead code'' (though the run-time overhead added by the assignment
|
|
|
|
|
would be trivial in any case). It might be conceivable for a compiler
|
|
|
|
|
to skip the semantic analysis and compilation of the constraints
|
|
|
|
|
function in the first place, which would make our function pointer
|
|
|
|
|
technique ineffective. However, this is unlikely because removal of
|
|
|
|
|
unnecessary code and functions is typically done in later stages of a
|
|
|
|
|
compiler. We have successfully used the function pointer technique
|
|
|
|
|
with GNU C++, Microsoft Visual C++, and several EDG-based compilers
|
|
|
|
|
(KAI C++, SGI MIPSpro). The following code shows how this technique
|
|
|
|
|
can be applied to the <tt>std::stable_sort()</tt> function:
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class RandomAccessIterator>
|
|
|
|
|
void stable_sort_constraints(RandomAccessIterator i) {
|
|
|
|
|
typename std::iterator_traits<RandomAccessIterator>
|
|
|
|
|
::difference_type n;
|
|
|
|
|
i += n; // exercise the requirements for RandomAccessIterator
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
template <class RandomAccessIterator>
|
|
|
|
|
void stable_sort(RandomAccessIterator first, RandomAccessIterator last) {
|
|
|
|
|
typedef void (*fptr_type)(RandomAccessIterator);
|
|
|
|
|
fptr_type x = &stable_sort_constraints;
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
There is often a large set of requirements that need to be checked,
|
|
|
|
|
and it would be cumbersome for the library implementor to write
|
|
|
|
|
constraint functions like <tt>stable_sort_constraints()</tt> for every
|
|
|
|
|
public function. Instead, we group sets of valid expressions
|
|
|
|
|
together, according to the definitions of the corresponding concepts.
|
|
|
|
|
For each concept we define a concept checking class template where the
|
|
|
|
|
template parameter is for the type to be checked. The class contains
|
|
|
|
|
a <tt>contraints()</tt> member function which exercises all of the
|
|
|
|
|
valid expressions of the concept. The objects used in the constraints
|
|
|
|
|
function, such as <tt>n</tt> and <tt>i</tt>, are declared as data
|
|
|
|
|
members of the concept checking class.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Iter>
|
|
|
|
|
struct RandomAccessIterator_concept {
|
|
|
|
|
void constraints() {
|
|
|
|
|
i += n;
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
typename std::iterator_traits<RandomAccessIterator>
|
|
|
|
|
::difference_type n;
|
|
|
|
|
Iter i;
|
|
|
|
|
...
|
|
|
|
|
};
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
We can still use the function pointer mechanism to cause instantiation
|
|
|
|
|
of the constraints function, however now it will be a member function
|
|
|
|
|
pointer. To make it easy for the library implementor to invoke the
|
|
|
|
|
concept checks, we wrap the member function pointer mechanism in a
|
|
|
|
|
function named <tt>function_requires()</tt>. The following code
|
|
|
|
|
snippet shows how to use <tt>function_requires()</tt> to make sure
|
|
|
|
|
that the iterator is a
|
|
|
|
|
<a
|
|
|
|
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
|
|
|
|
RandomAccessIterator</a>.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class RandomAccessIter>
|
|
|
|
|
void stable_sort(RandomAccessIter first, RandomAccessIter last)
|
|
|
|
|
{
|
|
|
|
|
function_requires< RandomAccessIteratorConcept<RandomAccessIter> >();
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
The definition of the <tt>function_requires()</tt> is as follows. The
|
|
|
|
|
<tt>Concept</tt> is the concept checking class that has been
|
|
|
|
|
instantiated with the modeling type. We assign the address of the
|
|
|
|
|
constraints member function to the function pointer <tt>x</tt>, which
|
|
|
|
|
causes the instantiation of the constraints function and checking of
|
|
|
|
|
the concept's valid expressions. We then assign <tt>x</tt> to
|
|
|
|
|
<tt>x</tt> to avoid unused variable compiler warnings, and wrap
|
|
|
|
|
everything in a do-while loop to prevent name collisions.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Concept>
|
|
|
|
|
void function_requires()
|
|
|
|
|
{
|
|
|
|
|
void (Concept::*x)() = BOOST_FPTR Concept::constraints;
|
|
|
|
|
ignore_unused_variable_warning(x);
|
|
|
|
|
}
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
To check the type parameters of class templates, we provide the
|
|
|
|
|
<tt>class_requires</tt> class which can be used inside the body of a
|
|
|
|
|
class definition (whereas <tt>function_requires()</tt> can only be
|
|
|
|
|
used inside of a function body). <tt>class_requires</tt> declares a
|
|
|
|
|
nested class template, where the template parameter is a function
|
|
|
|
|
pointer. We then use the nested class type in a typedef with the
|
|
|
|
|
function pointer type of the constraint function as the template
|
|
|
|
|
argument.
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Concept>
|
|
|
|
|
class class_requires
|
|
|
|
|
{
|
|
|
|
|
typedef void (Concept::* function_pointer)();
|
|
|
|
|
|
|
|
|
|
template <function_pointer Fptr>
|
|
|
|
|
struct dummy_struct { };
|
|
|
|
|
public:
|
|
|
|
|
typedef dummy_struct< BOOST_FPTR Concept::constraints > check;
|
|
|
|
|
};
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<tt>class_requires</tt> was not used in the implementation of the
|
|
|
|
|
Boost Concept Checking Library concept checks because several
|
|
|
|
|
compilers do not implement template parameters of function pointer
|
|
|
|
|
type.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h2><a name="reference">Reference</a></h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3><a name="functions">Functions</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Concept>
|
|
|
|
|
void function_requires();
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="classes">Classes</a></h3>
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Concept>
|
|
|
|
|
struct class_requires {
|
|
|
|
|
typedef ... check;
|
|
|
|
|
};
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
// Make sure that <i>Type1</i> and <i>Type2</i> are exactly the same type.
|
|
|
|
|
// If they are not, then the nested typedef for <tt>type</tt> will
|
|
|
|
|
// not exist and cause a compiler error.
|
|
|
|
|
template <class Type1, class Type2>
|
|
|
|
|
struct require_same {
|
|
|
|
|
typedef ... type;
|
|
|
|
|
};
|
|
|
|
|
// usage example
|
|
|
|
|
typedef typedef require_same<int,int>::type req1; // this will compile OK
|
|
|
|
|
typedef typedef require_same<int,float>::type req1; // this will cause a compiler error
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="basic-concepts">Basic Concept Checking Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class T> struct Integer_concept; // Is T a built-in integer type?
|
|
|
|
|
template <class T> struct SignedIntegerConcept; // Is T a built-in signed integer type?
|
|
|
|
|
template <class X, class Y> struct ConvertibleConcept; // Is X convertible to Y?
|
|
|
|
|
template <class T> struct AssignableConcept;
|
|
|
|
|
template <class T> struct DefaultConstructibleConcept;
|
|
|
|
|
template <class T> struct CopyConstructibleConcept;
|
|
|
|
|
template <class T> struct BooleanConcept;
|
|
|
|
|
template <class T> struct EqualityComparableConcept;
|
|
|
|
|
// Is class T equality comparable on the left side with type Left?
|
|
|
|
|
template <class T, class Left> struct LeftEqualityComparableConcept;
|
|
|
|
|
template <class T> struct LessThanComparableConcept;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="iterator-concepts">Iterator Concept Checking Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Iter> struct TrivialIteratorConcept;
|
|
|
|
|
template <class Iter> struct Mutable_TrivialIteratorConcept;
|
|
|
|
|
template <class Iter> struct InputIteratorConcept;
|
|
|
|
|
template <class Iter, class T> struct OutputIteratorConcept;
|
|
|
|
|
template <class Iter> struct ForwardIteratorConcept;
|
|
|
|
|
template <class Iter> struct Mutable_ForwardIteratorConcept;
|
|
|
|
|
template <class Iter> struct BidirectionalIteratorConcept;
|
|
|
|
|
template <class Iter> struct Mutable_BidirectionalIteratorConcept;
|
|
|
|
|
template <class Iter> struct RandomAccessIteratorConcept;
|
|
|
|
|
template <class Iter> struct Mutable_RandomAccessIteratorConcept;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="function-object-concepts">Function Object Concept Checking Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Func, class Return> struct GeneratorConcept;
|
|
|
|
|
template <class Func, class Return, class Arg> struct UnaryFunctionConcept;
|
|
|
|
|
template <class Func, class Return, class First, class Second> struct BinaryFunctionConcept;
|
|
|
|
|
template <class Func, class Arg> struct UnaryPredicateConcept;
|
|
|
|
|
template <class Func, class First, class Second> struct BinaryPredicateConcept;
|
|
|
|
|
template <class Func, class First, class Second> struct Const_BinaryPredicateConcept {;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="container-concepts">Container Concept Checking Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class C> struct ContainerConcept;
|
|
|
|
|
template <class C> struct Mutable_ContainerConcept;
|
|
|
|
|
|
|
|
|
|
template <class C> struct ForwardContainerConcept;
|
|
|
|
|
template <class C> struct Mutable_ForwardContainerConcept;
|
|
|
|
|
|
|
|
|
|
template <class C> struct ReversibleContainerConcept;
|
|
|
|
|
template <class C> struct Mutable_ReversibleContainerConcept;
|
|
|
|
|
|
|
|
|
|
template <class C> struct RandomAccessContainerConcept;
|
|
|
|
|
template <class C> struct Mutable_RandomAccessContainerConcept;
|
|
|
|
|
|
|
|
|
|
template <class C> struct SequenceConcept;
|
|
|
|
|
template <class C> struct FrontInsertionSequenceConcept;
|
|
|
|
|
template <class C> struct BackInsertionSequenceConcept;
|
|
|
|
|
|
|
|
|
|
template <class C> struct AssociativeContainerConcept;
|
|
|
|
|
template <class C> struct UniqueAssociativeContainerConcept;
|
|
|
|
|
template <class C> struct MultipleAssociativeContainerConcept;
|
|
|
|
|
template <class C> struct SimpleAssociativeContainerConcept;
|
|
|
|
|
template <class C> struct PairAssociativeContainerConcept;
|
|
|
|
|
template <class C> struct SortedAssociativeContainerConcept;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3><a name="basic-archetype">Basic Archetype Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
class null_archetype; // A type that models no concepts.
|
|
|
|
|
template <class Base = null_archetype> class default_constructible_archetype;
|
|
|
|
|
template <class Base = null_archetype> class assignable_archetype;
|
|
|
|
|
template <class Base = null_archetype> class copy_constructible_archetype;
|
|
|
|
|
template <class Left, class Base = null_archetype> class left_equality_comparable_archetype;
|
|
|
|
|
template <class Base = null_archetype> class equality_comparable_archetype;
|
|
|
|
|
template <class T, class Base = null_archetype> class convertible_to_archetype;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="iterator-archetype">Iterator Archetype Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class ValueType> class trivial_iterator_archetype;
|
|
|
|
|
template <class ValueType> class mutable_trivial_iterator_archetype;
|
|
|
|
|
template <class ValueType> class input_iterator_archetype;
|
|
|
|
|
template <class ValueType> class forward_iterator_archetype;
|
|
|
|
|
template <class ValueType> class bidirectional_iterator_archetype;
|
|
|
|
|
template <class ValueType> class random_access_iterator_archetype;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="function-object-archetype">Function Object Archetype Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
template <class Arg, class Return> class unary_function_archetype;
|
|
|
|
|
template <class Arg1, class Arg2, class Return> class binary_function_archetype;
|
|
|
|
|
template <class Arg> class predicate_archetype;
|
|
|
|
|
template <class Arg1, class Arg2> class binary_predicate_archetype;
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h3><a name="container-archetype">Container Archetype Classes</a></h3>
|
|
|
|
|
|
|
|
|
|
<pre>
|
|
|
|
|
UNDER CONSTRUCTION
|
|
|
|
|
</pre>
|
|
|
|
|
|
|
|
|
|
<h2><a name="history">History</a></h2>
|
|
|
|
|
|
|
|
|
|
An earlier version of this concept checking system was developed by
|
|
|
|
|
the author while working at SGI in their C++ compiler and library
|
|
|
|
|
group. The earlier version is now part of the SGI STL distribution. The
|
|
|
|
|
boost concept checking library differs from the concept checking in
|
|
|
|
|
the SGI STL in that the definition of concept checking classes has
|
|
|
|
|
been greatly simplified, at the price of less helpful verbiage in the
|
|
|
|
|
error messages.
|
|
|
|
|
|
|
|
|
|
<h2><a name="publications">Publications</a></h2>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li><a href="http://www.oonumerics.org/tmpw00/">
|
|
|
|
|
C++ Template Workshop 2000</a>, Concept Checking</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<h2><a name="acknowledgements">Acknowledgements</a></h2>
|
|
|
|
|
|
|
|
|
|
The idea to use function pointers to cause instantiation is due to
|
|
|
|
|
Alexander Stepanov. I am not sure of the origin of the idea to use
|
|
|
|
|
expressions to do up-front checking of templates, but it did appear in
|
|
|
|
|
D&E[
|
|
|
|
|
<a href="bibliography.html#stroustrup94:_design_evolution">2</a>].
|
|
|
|
|
Thanks to Matt Austern for his excellent documentation and
|
|
|
|
|
organization of the STL concepts, upon which these concept checks
|
|
|
|
|
are based. Thanks to Boost members for helpful comments and
|
|
|
|
|
reviews.
|
|
|
|
|
|
|
|
|
|
<br>
|
|
|
|
|
<HR>
|
|
|
|
|
<TABLE>
|
|
|
|
|
<TR valign=top>
|
|
|
|
|
<TD nowrap>Copyright © 2000</TD><TD>
|
|
|
|
|
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>,
|
|
|
|
|
Univ.of Notre Dame (<A
|
|
|
|
|
HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
|
|
|
|
</TD></TR></TABLE>
|
|
|
|
|
|
|
|
|
|
</BODY>
|
|
|
|
|
</HTML>
|