mirror of
https://github.com/boostorg/concept_check.git
synced 2025-07-31 13:07:33 +02:00
changing directory name, and reorganizing docs
[SVN r8410]
This commit is contained in:
70
bibliography.htm
Normal file
70
bibliography.htm
Normal file
@@ -0,0 +1,70 @@
|
||||
<HTML>
|
||||
<!--
|
||||
-- Copyright (c) Jeremy Siek 2000
|
||||
--
|
||||
-- Permission to use, copy, modify, distribute and sell this software
|
||||
-- and its documentation for any purpose is hereby granted without fee,
|
||||
-- provided that the above copyright notice appears in all copies and
|
||||
-- that both that copyright notice and this permission notice appear
|
||||
-- in supporting documentation. Silicon Graphics makes no
|
||||
-- representations about the suitability of this software for any
|
||||
-- purpose. It is provided "as is" without express or implied warranty.
|
||||
-->
|
||||
<Head>
|
||||
<Title>Boost Graph Library: Bibliography</Title>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||
ALINK="#ff0000">
|
||||
<IMG SRC="../../c++boost.gif"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
|
||||
<BR Clear>
|
||||
|
||||
|
||||
<H2>Bibliography</H2>
|
||||
|
||||
<DL COMMapCT>
|
||||
|
||||
<DD><P></P><DT><a name="alexandrescu99:_better_templ_error_messag">1</a>
|
||||
<DD>Andrei Alexandrescu<BR>
|
||||
<EM>Better Template Error Messages</EM>.<BR>
|
||||
C/C++ Users Journal, March, 1999.
|
||||
|
||||
|
||||
<DD><P></P><DT><a name="stroustrup94:_design_evolution">2</a>
|
||||
<DD>Bjarne Stroustrup<BR>
|
||||
<EM>Design and Evolution of C++</EM>.<BR>
|
||||
Addison-Wesley, 1994
|
||||
|
||||
<P></P><DT><A NAME="austern99:_gener_progr_stl">3</A>
|
||||
<DD>
|
||||
M. H. Austern.
|
||||
<BR><EM>Generic Programming and the STL</EM>.
|
||||
<BR>Professional computing series. Addison-Wesley, 1999.
|
||||
|
||||
<P></P><DT><A NAME="IB-H965502">4</A>
|
||||
<DD>
|
||||
David R. Musser and Atul Saini
|
||||
<BR><EM>STL Tutorial and Reference Guide</EM>.
|
||||
<BR>Professional computing series. Addison-Wesley, 1996.
|
||||
|
||||
<P></P><DT><A NAME="stepa.lee-1994:the.s:TR">5</A>
|
||||
<DD>
|
||||
A. A. Stepanov and M. Lee
|
||||
<BR><EM>The Standard Template Library</EM>.
|
||||
<BR>ISO Programming Language C++ Project, May 1994.
|
||||
<BR>X3J16/94-0095, WG21/N0482
|
||||
|
||||
|
||||
|
||||
</DL>
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 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>
|
30
class_concept_check_fail_expected.cpp
Normal file
30
class_concept_check_fail_expected.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
#include <boost/pending/concept_checks.hpp>
|
||||
|
||||
/*
|
||||
|
||||
This file verifies that class_requires of the Boost Concept Checking
|
||||
Library catches errors when it is suppose to.
|
||||
|
||||
*/
|
||||
|
||||
struct foo { };
|
||||
|
||||
using namespace boost;
|
||||
|
||||
class class_requires_test
|
||||
{
|
||||
BOOST_CLASS_REQUIRES(foo, EqualityComparableConcept);
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
class_requires_test x;
|
||||
return 0;
|
||||
}
|
37
class_concept_check_test.cpp
Normal file
37
class_concept_check_test.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
#include <boost/pending/concept_checks.hpp>
|
||||
|
||||
/*
|
||||
|
||||
This file verifies that the BOOST_CLASS_REQUIRES macro of the Boost
|
||||
Concept Checking Library does not cause errors when it is not suppose
|
||||
to.
|
||||
|
||||
*/
|
||||
|
||||
struct foo { bool operator()(int) { return true; } };
|
||||
struct bar { bool operator()(int, char) { return true; } };
|
||||
|
||||
using namespace boost;
|
||||
|
||||
class class_requires_test
|
||||
{
|
||||
BOOST_CLASS_REQUIRES(int, EqualityComparableConcept);
|
||||
typedef int* int_ptr; typedef const int* const_int_ptr;
|
||||
BOOST_CLASS_REQUIRES2(int_ptr, const_int_ptr, Comparable2Concept);
|
||||
BOOST_CLASS_REQUIRES3(foo, bool, int, UnaryFunctionConcept);
|
||||
BOOST_CLASS_REQUIRES4(bar, bool, int, char, BinaryFunctionConcept);
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
class_requires_test x;
|
||||
ignore_unused_variable_warning(x);
|
||||
return 0;
|
||||
}
|
228
concept_check.htm
Normal file
228
concept_check.htm
Normal file
@@ -0,0 +1,228 @@
|
||||
<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 (BCCL) 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.htm">Using Concept Checks</a></LI>
|
||||
<LI><a href="./creating_concept_checks.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>
|
||||
<LI><a href="./history.htm">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>
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF="../../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>
|
23
concept_check_fail_expected.cpp
Normal file
23
concept_check_fail_expected.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
#include <boost/pending/concept_checks.hpp>
|
||||
|
||||
/*
|
||||
|
||||
This file verifies that function_requires() of the Boost Concept
|
||||
Checking Library catches errors when it is suppose to.
|
||||
|
||||
*/
|
||||
|
||||
struct foo { };
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
boost::function_requires< boost::EqualityComparableConcept<foo> >();
|
||||
return 0;
|
||||
}
|
185
concept_check_test.cpp
Normal file
185
concept_check_test.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
#include <boost/pending/concept_checks.hpp>
|
||||
#include <boost/pending/concept_archetypes.hpp>
|
||||
|
||||
/*
|
||||
|
||||
This file verifies that the BOOST_FUNCTION_REQUIRES macros of the
|
||||
Boost Concept Checking Library do not cause errors when they are not
|
||||
suppose to and verifies that the concept archetypes meet the
|
||||
requirements of their matching concepts.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
//===========================================================================
|
||||
// Basic Concepts
|
||||
{
|
||||
typedef default_constructible_archetype<> foo;
|
||||
function_requires< DefaultConstructibleConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef assignable_archetype<> foo;
|
||||
function_requires< AssignableConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef copy_constructible_archetype<> foo;
|
||||
function_requires< CopyConstructibleConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef sgi_assignable_archetype<> foo;
|
||||
function_requires< SGIAssignableConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef copy_constructible_archetype<> foo;
|
||||
typedef convertible_to_archetype<foo> convertible_to_foo;
|
||||
function_requires< ConvertibleConcept<convertible_to_foo, foo> >();
|
||||
}
|
||||
{
|
||||
function_requires< ConvertibleConcept<boolean_archetype, bool> >();
|
||||
}
|
||||
{
|
||||
typedef equality_comparable_archetype<> foo;
|
||||
function_requires< EqualityComparableConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef less_than_comparable_archetype<> foo;
|
||||
function_requires< LessThanComparableConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef comparable_archetype<> foo;
|
||||
function_requires< ComparableConcept<foo> >();
|
||||
}
|
||||
{
|
||||
typedef equal_op_first_archetype<> First;
|
||||
typedef equal_op_second_archetype<> Second;
|
||||
function_requires< EqualOpConcept<First, Second> >();
|
||||
}
|
||||
{
|
||||
typedef not_equal_op_first_archetype<> First;
|
||||
typedef not_equal_op_second_archetype<> Second;
|
||||
function_requires< NotEqualOpConcept<First, Second> >();
|
||||
}
|
||||
{
|
||||
typedef less_than_op_first_archetype<> First;
|
||||
typedef less_than_op_second_archetype<> Second;
|
||||
function_requires< LessThanOpConcept<First, Second> >();
|
||||
}
|
||||
{
|
||||
typedef less_equal_op_first_archetype<> First;
|
||||
typedef less_equal_op_second_archetype<> Second;
|
||||
function_requires< LessEqualOpConcept<First, Second> >();
|
||||
}
|
||||
{
|
||||
typedef greater_than_op_first_archetype<> First;
|
||||
typedef greater_than_op_second_archetype<> Second;
|
||||
function_requires< GreaterThanOpConcept<First, Second> >();
|
||||
}
|
||||
{
|
||||
typedef greater_equal_op_first_archetype<> First;
|
||||
typedef greater_equal_op_second_archetype<> Second;
|
||||
function_requires< GreaterEqualOpConcept<First, Second> >();
|
||||
}
|
||||
|
||||
{
|
||||
typedef copy_constructible_archetype<> Return;
|
||||
typedef plus_op_first_archetype<Return> First;
|
||||
typedef plus_op_second_archetype<Return> Second;
|
||||
function_requires< PlusOpConcept<Return, First, Second> >();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Function Object Concepts
|
||||
|
||||
{
|
||||
typedef generator_archetype<null_archetype<> > foo;
|
||||
function_requires< GeneratorConcept<foo, null_archetype<> > >();
|
||||
}
|
||||
{
|
||||
function_requires< GeneratorConcept< void_generator_archetype, void > >();
|
||||
}
|
||||
{
|
||||
typedef unary_function_archetype<int, int> F;
|
||||
function_requires< UnaryFunctionConcept<F, int, int> >();
|
||||
}
|
||||
{
|
||||
typedef binary_function_archetype<int, int, int> F;
|
||||
function_requires< BinaryFunctionConcept<F, int, int, int> >();
|
||||
}
|
||||
{
|
||||
typedef unary_predicate_archetype<int> F;
|
||||
function_requires< UnaryPredicateConcept<F, int> >();
|
||||
}
|
||||
{
|
||||
typedef binary_predicate_archetype<int, int> F;
|
||||
function_requires< BinaryPredicateConcept<F, int, int> >();
|
||||
typedef const_binary_predicate_archetype<int, int> const_F;
|
||||
function_requires< Const_BinaryPredicateConcept<const_F, int, int> >();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Iterator Concepts
|
||||
{
|
||||
typedef trivial_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< TrivialIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef mutable_trivial_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< Mutable_TrivialIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef input_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< InputIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef output_iterator_archetype Iter;
|
||||
function_requires< OutputIteratorConcept<Iter, int> >();
|
||||
}
|
||||
{
|
||||
typedef forward_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< ForwardIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef forward_iterator_archetype<assignable_archetype<> > Iter;
|
||||
function_requires< Mutable_ForwardIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef bidirectional_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< BidirectionalIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef bidirectional_iterator_archetype<assignable_archetype<> > Iter;
|
||||
function_requires< Mutable_BidirectionalIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef random_access_iterator_archetype<null_archetype<> > Iter;
|
||||
function_requires< RandomAccessIteratorConcept<Iter> >();
|
||||
}
|
||||
{
|
||||
typedef random_access_iterator_archetype<assignable_archetype<> > Iter;
|
||||
function_requires< Mutable_RandomAccessIteratorConcept<Iter> >();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Container Concepts
|
||||
|
||||
{
|
||||
|
||||
function_requires< ContainerConcept< > >();
|
||||
}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
96
concept_covering.htm
Normal file
96
concept_covering.htm
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
<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>
|
||||
|
72
creating_concepts.htm
Normal file
72
creating_concepts.htm
Normal file
@@ -0,0 +1,72 @@
|
||||
<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).
|
29
history.htm
Normal file
29
history.htm
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
<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.
|
133
implementation.htm
Normal file
133
implementation.htm
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
|
||||
<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.
|
||||
|
106
prog_with_concepts.htm
Normal file
106
prog_with_concepts.htm
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
<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).
|
152
reference.htm
Normal file
152
reference.htm
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
<h2><a name="reference">Reference</a></h2>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
90
stl_concept_check.cpp
Normal file
90
stl_concept_check.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
//
|
||||
// This file checks to see if various standard container
|
||||
// implementations live up to requirements specified in the C++
|
||||
// standard. As many implementations do not live to the requirements,
|
||||
// it is not uncommon for this file to fail to compile. The
|
||||
// BOOST_HIDE_EXPECTED_ERRORS macro is provided here if you want to
|
||||
// see as much of this file compile as possible.
|
||||
//
|
||||
|
||||
#include <boost/pending/concept_checks.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#ifndef BOOST_NO_SLIST
|
||||
#include <slist>
|
||||
#endif
|
||||
|
||||
//#define BOOST_HIDE_EXPECTED_ERRORS
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#if defined(_ITERATOR_) && defined(BOOST_HIDE_EXPECTED_ERRORS)
|
||||
// VC++ STL implementation is not standard conformant and
|
||||
// fails to pass these concept checks
|
||||
#else
|
||||
typedef std::vector<int> Vector;
|
||||
typedef std::deque<int> Deque;
|
||||
typedef std::list<int> List;
|
||||
|
||||
// VC++ missing pointer and const_pointer typedefs
|
||||
function_requires< Mutable_RandomAccessContainerConcept<Vector> >();
|
||||
function_requires< BackInsertionSequenceConcept<Vector> >();
|
||||
|
||||
#if !(defined(__GNUC__) && defined(BOOST_HIDE_EXPECTED_ERRORS))
|
||||
#if !(defined(__sgi) && defined(BOOST_HIDE_EXPECTED_ERRORS))
|
||||
// old deque iterator missing n + iter operation
|
||||
function_requires< Mutable_RandomAccessContainerConcept<Deque> >();
|
||||
#endif
|
||||
// warnings about signed and unsigned in old deque version
|
||||
function_requires< FrontInsertionSequenceConcept<Deque> >();
|
||||
function_requires< BackInsertionSequenceConcept<Deque> >();
|
||||
#endif
|
||||
|
||||
// VC++ missing pointer and const_pointer typedefs
|
||||
function_requires< Mutable_ReversibleContainerConcept<List> >();
|
||||
function_requires< FrontInsertionSequenceConcept<List> >();
|
||||
function_requires< BackInsertionSequenceConcept<List> >();
|
||||
|
||||
#ifndef BOOST_NO_SLIST
|
||||
typedef std::slist<int> SList;
|
||||
function_requires< FrontInsertionSequenceConcept<SList> >();
|
||||
#endif
|
||||
|
||||
typedef std::set<int> Set;
|
||||
typedef std::multiset<int> MultiSet;
|
||||
typedef std::map<int,int> Map;
|
||||
typedef std::multimap<int,int> MultiMap;
|
||||
|
||||
function_requires< SortedAssociativeContainerConcept<Set> >();
|
||||
function_requires< SimpleAssociativeContainerConcept<Set> >();
|
||||
function_requires< UniqueAssociativeContainerConcept<Set> >();
|
||||
|
||||
function_requires< SortedAssociativeContainerConcept<MultiSet> >();
|
||||
function_requires< SimpleAssociativeContainerConcept<MultiSet> >();
|
||||
function_requires< MultipleAssociativeContainerConcept<MultiSet> >();
|
||||
|
||||
function_requires< SortedAssociativeContainerConcept<Map> >();
|
||||
function_requires< UniqueAssociativeContainerConcept<Map> >();
|
||||
function_requires< PairAssociativeContainerConcept<Map> >();
|
||||
|
||||
function_requires< SortedAssociativeContainerConcept<MultiMap> >();
|
||||
function_requires< MultipleAssociativeContainerConcept<MultiMap> >();
|
||||
function_requires< PairAssociativeContainerConcept<MultiMap> >();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
181
using_concept_check.htm
Normal file
181
using_concept_check.htm
Normal file
@@ -0,0 +1,181 @@
|
||||
<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>
|
||||
|
Reference in New Issue
Block a user