mirror of
https://github.com/boostorg/utility.git
synced 2025-10-06 14:00:55 +02:00
Compare commits
45 Commits
svn-branch
...
boost-1.20
Author | SHA1 | Date | |
---|---|---|---|
|
b7551024da | ||
|
6a0c3e92a0 | ||
|
cba48df8e3 | ||
|
a0e8d1bf36 | ||
|
912dedaca7 | ||
|
7dd90c3919 | ||
|
7c3a25a377 | ||
|
c8fbca2d44 | ||
|
f7ed0aaeed | ||
|
6e78270140 | ||
|
ba354377d5 | ||
|
353c030918 | ||
|
331a2b8282 | ||
|
4bd6909ea1 | ||
|
26119613e1 | ||
|
45bfe0b607 | ||
|
ce2f573ab2 | ||
|
66d5cc43f3 | ||
|
e8265e09a3 | ||
|
860cf0b321 | ||
|
89c74708d7 | ||
|
74c8680350 | ||
|
3cd9f5b623 | ||
|
0936110741 | ||
|
6161ce15c7 | ||
|
28594a22f1 | ||
|
656517b059 | ||
|
ad576863b4 | ||
|
775be75366 | ||
|
7ae6e5bac9 | ||
|
c5915c23e7 | ||
|
1f2a827df3 | ||
|
f51ee4ef2e | ||
|
75aadf0509 | ||
|
4f9b0bcb9b | ||
|
9628e5adb0 | ||
|
b5418034ff | ||
|
6dda4704e1 | ||
|
79c360a1d8 | ||
|
b70ad177bb | ||
|
7b02fdb1d9 | ||
|
73acec35c9 | ||
|
3ddb9abc3c | ||
|
5b06dd0d0d | ||
|
daf7829ffa |
116
Assignable.html
Normal file
116
Assignable.html
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<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>Assignable</Title>
|
||||||
|
</HEAD>
|
||||||
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||||
|
ALINK="#ff0000">
|
||||||
|
<IMG SRC="../../c++boost.gif"
|
||||||
|
ALT="C++ Boost" width="277" height="86">
|
||||||
|
<!--end header-->
|
||||||
|
<BR Clear>
|
||||||
|
<H1>Assignable</H1>
|
||||||
|
|
||||||
|
<h3>Description</h3>
|
||||||
|
A type is Assignable if it is possible to assign one object of the type
|
||||||
|
to another object of that type.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Notation</h3>
|
||||||
|
<Table>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is type that is a model of Assignable
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>t</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is an object of type <tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>u</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is an object of type <tt>T</tt> or possibly <tt>const T</tt>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<h3>Definitions</h3>
|
||||||
|
<h3>Valid expressions</h3>
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TH>
|
||||||
|
Name
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Expression
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Return type
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Semantics
|
||||||
|
</TH>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Assignment
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>t = u</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T&</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>t</tt> is equivalent to <tt>u</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<h3>Models</h3>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><tt>int</tt>
|
||||||
|
<LI><tt>std::pair</tt>
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
<h3>See also</h3>
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/DefaultConstructible.html">DefaultConstructible</A>
|
||||||
|
and
|
||||||
|
<A href="./CopyConstructible.html">CopyConstructible</A>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<HR>
|
||||||
|
<TABLE>
|
||||||
|
<TR valign=top>
|
||||||
|
<TD nowrap>Copyright © 2000</TD><TD>
|
||||||
|
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||||
|
</TD></TR></TABLE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
210
CopyConstructible.html
Normal file
210
CopyConstructible.html
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<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>CopyConstructible</Title>
|
||||||
|
</HEAD>
|
||||||
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||||
|
ALINK="#ff0000">
|
||||||
|
<IMG SRC="../../c++boost.gif"
|
||||||
|
ALT="C++ Boost" width="277" height="86">
|
||||||
|
<!--end header-->
|
||||||
|
<BR Clear>
|
||||||
|
<H1>CopyConstructible</H1>
|
||||||
|
|
||||||
|
<h3>Description</h3>
|
||||||
|
A type is CopyConstructible if it is possible to copy objects of that
|
||||||
|
type.
|
||||||
|
|
||||||
|
<h3>Notation</h3>
|
||||||
|
<Table>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is type that is a model of CopyConstructible
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>t</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is an object of type <tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>u</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
is an object of type <tt>const T</tt>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<h3>Definitions</h3>
|
||||||
|
<h3>Valid expressions</h3>
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TH>
|
||||||
|
Name
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Expression
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Return type
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Semantics
|
||||||
|
</TH>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Copy constructor
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T(t)</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>t</tt> is equivalent to <tt>T(t)</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Copy constructor
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<pre>
|
||||||
|
T(u)
|
||||||
|
</pre>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>u</tt> is equivalent to <tt>T(u)</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Destructor
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<pre>
|
||||||
|
t.~T()
|
||||||
|
</pre>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Address Operator
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<pre>
|
||||||
|
&t
|
||||||
|
</pre>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T*</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
denotes the address of <tt>t</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Address Operator
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<pre>
|
||||||
|
&u
|
||||||
|
</pre>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>T*</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
denotes the address of <tt>u</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<h3>Models</h3>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><tt>int</tt>
|
||||||
|
<LI><tt>std::pair</tt>
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
<h3>Concept Checking Class</h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
template <class T>
|
||||||
|
struct CopyConstructibleConcept
|
||||||
|
{
|
||||||
|
void constraints() {
|
||||||
|
T a(b); // require copy constructor
|
||||||
|
T* ptr = &a; // require address of operator
|
||||||
|
const_constraints(a);
|
||||||
|
ignore_unused_variable_warning(ptr);
|
||||||
|
}
|
||||||
|
void const_constraints(const T& a) {
|
||||||
|
T c(a); // require const copy constructor
|
||||||
|
const T* ptr = &a; // require const address of operator
|
||||||
|
ignore_unused_variable_warning(c);
|
||||||
|
ignore_unused_variable_warning(ptr);
|
||||||
|
}
|
||||||
|
T b;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h3>See also</h3>
|
||||||
|
<A
|
||||||
|
href="http://www.sgi.com/Technology/STL/DefaultConstructible.html">DefaultConstructible</A>
|
||||||
|
and
|
||||||
|
<A href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</A>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<HR>
|
||||||
|
<TABLE>
|
||||||
|
<TR valign=top>
|
||||||
|
<TD nowrap>Copyright © 2000</TD><TD>
|
||||||
|
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||||
|
</TD></TR></TABLE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
212
LessThanComparable.html
Normal file
212
LessThanComparable.html
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
<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.
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
-- Copyright (c) 1996-1999
|
||||||
|
-- Silicon Graphics Computer Systems, Inc.
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- Copyright (c) 1994
|
||||||
|
-- Hewlett-Packard Company
|
||||||
|
--
|
||||||
|
-- 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. Hewlett-Packard Company makes no
|
||||||
|
-- representations about the suitability of this software for any
|
||||||
|
-- purpose. It is provided "as is" without express or implied warranty.
|
||||||
|
--
|
||||||
|
-->
|
||||||
|
<Head>
|
||||||
|
<Title>LessThanComparable</Title>
|
||||||
|
</Head>
|
||||||
|
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||||
|
ALINK="#ff0000">
|
||||||
|
<IMG SRC="../../c++boost.gif"
|
||||||
|
ALT="C++ Boost" width="277" height="86">
|
||||||
|
<!--end header-->
|
||||||
|
<BR Clear>
|
||||||
|
<H1>LessThanComparable</H1>
|
||||||
|
|
||||||
|
<h3>Description</h3>
|
||||||
|
A type is LessThanComparable if it is ordered: it must
|
||||||
|
be possible to compare two objects of that type using <tt>operator<</tt>, and
|
||||||
|
<tt>operator<</tt> must be a strict weak ordering relation.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Refinement of</h3>
|
||||||
|
<h3>Associated types</h3>
|
||||||
|
<h3>Notation</h3>
|
||||||
|
<Table>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>X</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
A type that is a model of LessThanComparable
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x</tt>, <tt>y</tt>, <tt>z</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Object of type <tt>X</tt>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3>Definitions</h3>
|
||||||
|
Consider the relation <tt>!(x < y) && !(y < x)</tt>. If this relation is
|
||||||
|
transitive (that is, if <tt>!(x < y) && !(y < x) && !(y < z) && !(z < y)</tt>
|
||||||
|
implies <tt>!(x < z) && !(z < x)</tt>), then it satisfies the mathematical
|
||||||
|
definition of an equivalence relation. In this case, <tt>operator<</tt>
|
||||||
|
is a <i>strict weak ordering</i>.
|
||||||
|
<P>
|
||||||
|
If <tt>operator<</tt> is a strict weak ordering, and if each equivalence class
|
||||||
|
has only a single element, then <tt>operator<</tt> is a <i>total ordering</i>.
|
||||||
|
<h3>Valid expressions</h3>
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TH>
|
||||||
|
Name
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Expression
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Type requirements
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Return type
|
||||||
|
</TH>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Less
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x < y</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Convertible to <tt>bool</tt>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Expression semantics</h3>
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TH>
|
||||||
|
Name
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Expression
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Precondition
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Semantics
|
||||||
|
</TH>
|
||||||
|
<TH>
|
||||||
|
Postcondition
|
||||||
|
</TH>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Less
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x < y</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x</tt> and <tt>y</tt> are in the domain of <tt><</tt>
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
|
||||||
|
</TD>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Complexity guarantees</h3>
|
||||||
|
<h3>Invariants</h3>
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Irreflexivity
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x < x</tt> must be false.
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Antisymmetry
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x < y</tt> implies !(y < x) <A href="#2">[2]</A>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
|
<TD VAlign=top>
|
||||||
|
Transitivity
|
||||||
|
</TD>
|
||||||
|
<TD VAlign=top>
|
||||||
|
<tt>x < y</tt> and <tt>y < z</tt> implies <tt>x < z</tt> <A href="#3">[3]</A>
|
||||||
|
</TD>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3>Models</h3>
|
||||||
|
<UL>
|
||||||
|
<LI>
|
||||||
|
int
|
||||||
|
</UL>
|
||||||
|
<h3>Notes</h3>
|
||||||
|
<P><A name="1">[1]</A>
|
||||||
|
Only <tt>operator<</tt> is fundamental; the other inequality operators
|
||||||
|
are essentially syntactic sugar.
|
||||||
|
<P><A name="2">[2]</A>
|
||||||
|
Antisymmetry is a theorem, not an axiom: it follows from
|
||||||
|
irreflexivity and transitivity.
|
||||||
|
<P><A name="3">[3]</A>
|
||||||
|
Because of irreflexivity and transitivity, <tt>operator<</tt> always
|
||||||
|
satisfies the definition of a <i>partial ordering</i>. The definition of
|
||||||
|
a <i>strict weak ordering</i> is stricter, and the definition of a
|
||||||
|
<i>total ordering</i> is stricter still.
|
||||||
|
<h3>See also</h3>
|
||||||
|
<A href="http://www.sgi.com/Technology/STL/EqualityComparable.html">EqualityComparable</A>, <A href="http://www.sgi.com/Technology/STL/StrictWeakOrdering.html">StrictWeakOrdering</A>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<HR>
|
||||||
|
<TABLE>
|
||||||
|
<TR valign=top>
|
||||||
|
<TD nowrap>Copyright © 2000</TD><TD>
|
||||||
|
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||||
|
</TD></TR></TABLE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
92
MultiPassInputIterator.html
Normal file
92
MultiPassInputIterator.html
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<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>MultiPassInputIterator</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>
|
||||||
|
<A NAME="concept:MultiPassInputIterator"></A>
|
||||||
|
MultiPassInputIterator
|
||||||
|
</H2>
|
||||||
|
|
||||||
|
This concept is a refinement of <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</a>,
|
||||||
|
adding the requirements that the iterator can be used to make multiple
|
||||||
|
passes through a range, and that if <TT>it1 == it2</TT> and
|
||||||
|
<TT>it1</TT> is dereferenceable then <TT>++it1 == ++it2</TT>. The
|
||||||
|
MultiPassInputIterator is very similar to the <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a>. The
|
||||||
|
only difference is that a <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a>
|
||||||
|
requires the <TT>reference</TT> type to be <TT>value_type&</TT>, whereas
|
||||||
|
MultiPassInputIterator is like <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</a>
|
||||||
|
in that the <TT>reference</TT> type merely has to be convertible to
|
||||||
|
<TT>value_type</TT>.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Design Notes</h3>
|
||||||
|
|
||||||
|
comments by Valentin Bonnard:
|
||||||
|
|
||||||
|
<p> I think that introducing MultiPassInputIterator isn't the right
|
||||||
|
solution. Do you also want to define MultiPassBidirectionnalIterator
|
||||||
|
and MultiPassRandomAccessIterator ? I don't, definitly. It only
|
||||||
|
confuses the issue. The problem lies into the existing hierarchy of
|
||||||
|
iterators, which mixes movabillity, modifiabillity and lvalue-ness,
|
||||||
|
and these are clearly independant.
|
||||||
|
|
||||||
|
<p> The terms Forward, Bidirectionnal and RandomAccess are about
|
||||||
|
movabillity and shouldn't be used to mean anything else. In a
|
||||||
|
completly orthogonal way, iterators can be immutable, mutable, or
|
||||||
|
neither. Lvalueness of iterators is also orthogonal with
|
||||||
|
immutabillity. With these clean concepts, your MultiPassInputIterator
|
||||||
|
is just called a ForwardIterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Other translations are:<br>
|
||||||
|
std::ForwardIterator -> ForwardIterator & LvalueIterator<br>
|
||||||
|
std::BidirectionnalIterator -> BidirectionnalIterator & LvalueIterator<br>
|
||||||
|
std::RandomAccessIterator -> RandomAccessIterator & LvalueIterator<br>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that in practice the only operation not allowed on my
|
||||||
|
ForwardIterator which is allowed on std::ForwardIterator is
|
||||||
|
<tt>&*it</tt>. I think that <tt>&*</tt> is rarely needed in generic code.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
reply by Jeremy Siek:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The above analysis by Valentin is right on. Of course, there is
|
||||||
|
the problem with backward compatibility. The current STL implementations
|
||||||
|
are based on the old definition of ForwardIterator. The right course
|
||||||
|
of action is to get ForwardIterator, etc. changed in the C++ standard.
|
||||||
|
Once that is done we can drop MultiPassInputIterator.
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
@@ -53,7 +53,7 @@ using std::cin;
|
|||||||
namespace opt{
|
namespace opt{
|
||||||
|
|
||||||
//
|
//
|
||||||
// algorithm destroy_arry:
|
// algorithm destroy_array:
|
||||||
// The reverse of std::unitialized_copy, takes a block of
|
// The reverse of std::unitialized_copy, takes a block of
|
||||||
// unitialized memory and calls destructors on all objects therein.
|
// unitialized memory and calls destructors on all objects therein.
|
||||||
//
|
//
|
||||||
@@ -196,7 +196,7 @@ struct filler<true>
|
|||||||
template <typename I, typename T>
|
template <typename I, typename T>
|
||||||
static void do_fill(I first, I last, T val)
|
static void do_fill(I first, I last, T val)
|
||||||
{
|
{
|
||||||
memset(first, val, last-first);
|
std::memset(first, val, last-first);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -421,3 +421,4 @@ int main()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -27,10 +27,16 @@ never occur, and that parameters are passed in the most efficient
|
|||||||
manner possible (see <a href="#examples">examples</a>). In each
|
manner possible (see <a href="#examples">examples</a>). In each
|
||||||
case if your existing practice is to use the type defined on the
|
case if your existing practice is to use the type defined on the
|
||||||
left, then replace it with the call_traits defined type on the
|
left, then replace it with the call_traits defined type on the
|
||||||
right. Note that for compilers that do not support partial
|
right. </p>
|
||||||
specialization, no benefit will occur from using call_traits: the
|
|
||||||
call_traits defined types will always be the same as the existing
|
<p>Note that for compilers that do not support either partial
|
||||||
practice in this case.</p>
|
specialization or member templates, no benefit will occur from
|
||||||
|
using call_traits: the call_traits defined types will always be
|
||||||
|
the same as the existing practice in this case. In addition if
|
||||||
|
only member templates and not partial template specialisation is
|
||||||
|
support by the compiler (for example Visual C++ 6) then call_traits
|
||||||
|
can not be used with array types (although it can be used to
|
||||||
|
solve the reference to reference problem).</p>
|
||||||
|
|
||||||
<table border="0" cellpadding="7" cellspacing="1" width="797">
|
<table border="0" cellpadding="7" cellspacing="1" width="797">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -569,7 +575,9 @@ std::pair<
|
|||||||
degraded to pointers if the deduced types are arrays, similar
|
degraded to pointers if the deduced types are arrays, similar
|
||||||
situations occur in the standard binders and adapters: in
|
situations occur in the standard binders and adapters: in
|
||||||
principle in any function that "wraps" a temporary
|
principle in any function that "wraps" a temporary
|
||||||
whose type is deduced.</p>
|
whose type is deduced. Note that the function arguments to make_pair
|
||||||
|
are not expressed in terms of call_traits: doing so would prevent
|
||||||
|
template argument deduction from functioning.</p>
|
||||||
|
|
||||||
<h4><a name="ex4"></a>Example 4 (optimising fill):</h4>
|
<h4><a name="ex4"></a>Example 4 (optimising fill):</h4>
|
||||||
|
|
||||||
@@ -632,6 +640,14 @@ Exactly how much mileage you will get from this depends upon your
|
|||||||
compiler - we could really use some accurate benchmarking
|
compiler - we could really use some accurate benchmarking
|
||||||
software as part of boost for cases like this.</p>
|
software as part of boost for cases like this.</p>
|
||||||
|
|
||||||
|
<p>Note that the function arguments to fill are not expressed in
|
||||||
|
terms of call_traits: doing so would prevent template argument
|
||||||
|
deduction from functioning. Instead fill acts as a "thin
|
||||||
|
wrapper" that is there to perform template argument
|
||||||
|
deduction, the compiler will optimise away the call to fill all
|
||||||
|
together, replacing it with the call to filler<>::do_fill,
|
||||||
|
which does use call_traits.</p>
|
||||||
|
|
||||||
<h3>Rationale</h3>
|
<h3>Rationale</h3>
|
||||||
|
|
||||||
<p>The following notes are intended to briefly describe the
|
<p>The following notes are intended to briefly describe the
|
||||||
@@ -713,7 +729,7 @@ specialisation).</p>
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<p>Revised 18 June 2000</p>
|
<p>Revised 01 September 2000</p>
|
||||||
|
|
||||||
<p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify,
|
<p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify,
|
||||||
sell and distribute this document is granted provided this
|
sell and distribute this document is granted provided this
|
||||||
|
@@ -1,3 +1,13 @@
|
|||||||
|
// boost::compressed_pair test program
|
||||||
|
|
||||||
|
// (C) Copyright John Maddock 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.
|
||||||
|
|
||||||
|
// standalone test program for <boost/call_traits.hpp>
|
||||||
|
// 03 Oct 2000:
|
||||||
|
// Enabled extra tests for VC6.
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -6,12 +16,7 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <boost/call_traits.hpp>
|
#include <boost/call_traits.hpp>
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
#include "type_traits_test.hpp"
|
||||||
// turn off some warnings, the way we do the tests will generate a *lot* of these
|
|
||||||
// this is a result of the tests not call_traits itself....
|
|
||||||
#pragma option -w-8004 -w-ccc -w-rch -w-eff -w-aus
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// struct contained models a type that contains a type (for example std::pair)
|
// struct contained models a type that contains a type (for example std::pair)
|
||||||
// arrays are contained by value, and have to be treated as a special case:
|
// arrays are contained by value, and have to be treated as a special case:
|
||||||
@@ -113,7 +118,7 @@ void checker<T>::operator()(param_type p)
|
|||||||
assert(t == c.get());
|
assert(t == c.get());
|
||||||
assert(t == c.const_get());
|
assert(t == c.const_get());
|
||||||
|
|
||||||
cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
|
//cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
|
||||||
cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained<T>::value).name() << endl;
|
cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained<T>::value).name() << endl;
|
||||||
cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained<T>::get).name() << endl;
|
cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained<T>::get).name() << endl;
|
||||||
cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained<T>::const_get).name() << endl;
|
cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained<T>::const_get).name() << endl;
|
||||||
@@ -178,30 +183,6 @@ struct UDT
|
|||||||
bool operator == (const UDT& v){ return v.i_ == i_; }
|
bool operator == (const UDT& v){ return v.i_ == i_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// define tests here
|
|
||||||
unsigned failures = 0;
|
|
||||||
unsigned test_count = 0;
|
|
||||||
|
|
||||||
#define value_test(v, x) ++test_count;\
|
|
||||||
if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
|
||||||
|
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(boost::is_same<v, x>::value == false){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << typeid(boost::is_same<v, x>).name() << "::value is false" << std::endl; }
|
|
||||||
#else
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(typeid(v) != typeid(x)){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
checker<UDT> c1;
|
checker<UDT> c1;
|
||||||
@@ -211,17 +192,18 @@ int main()
|
|||||||
int i = 2;
|
int i = 2;
|
||||||
c2(i);
|
c2(i);
|
||||||
int* pi = &i;
|
int* pi = &i;
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
checker<int*> c3;
|
checker<int*> c3;
|
||||||
c3(pi);
|
c3(pi);
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
checker<int&> c4;
|
checker<int&> c4;
|
||||||
c4(i);
|
c4(i);
|
||||||
checker<const int&> c5;
|
checker<const int&> c5;
|
||||||
c5(i);
|
c5(i);
|
||||||
|
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
int a[2] = {1,2};
|
int a[2] = {1,2};
|
||||||
checker<int[2]> c6;
|
checker<int[2]> c6;
|
||||||
c6(a);
|
c6(a);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_wrap(wrap(2), 2);
|
check_wrap(wrap(2), 2);
|
||||||
@@ -250,7 +232,7 @@ int main()
|
|||||||
type_test(int*&, boost::call_traits<int*>::reference)
|
type_test(int*&, boost::call_traits<int*>::reference)
|
||||||
type_test(int*const&, boost::call_traits<int*>::const_reference)
|
type_test(int*const&, boost::call_traits<int*>::const_reference)
|
||||||
type_test(int*const, boost::call_traits<int*>::param_type)
|
type_test(int*const, boost::call_traits<int*>::param_type)
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
type_test(int&, boost::call_traits<int&>::value_type)
|
type_test(int&, boost::call_traits<int&>::value_type)
|
||||||
type_test(int&, boost::call_traits<int&>::reference)
|
type_test(int&, boost::call_traits<int&>::reference)
|
||||||
type_test(const int&, boost::call_traits<int&>::const_reference)
|
type_test(const int&, boost::call_traits<int&>::const_reference)
|
||||||
@@ -261,7 +243,7 @@ int main()
|
|||||||
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
||||||
type_test(int&, boost::call_traits<cr_type>::param_type)
|
type_test(int&, boost::call_traits<cr_type>::param_type)
|
||||||
#else
|
#else
|
||||||
std::cout << "GNU C++ cannot instantiate call_traits<cr_type>, skipping four tests (4 errors)" << std::endl;
|
std::cout << "Your compiler cannot instantiate call_traits<int&const>, skipping four tests (4 errors)" << std::endl;
|
||||||
failures += 4;
|
failures += 4;
|
||||||
test_count += 4;
|
test_count += 4;
|
||||||
#endif
|
#endif
|
||||||
@@ -269,6 +251,7 @@ int main()
|
|||||||
type_test(const int&, boost::call_traits<const int&>::reference)
|
type_test(const int&, boost::call_traits<const int&>::reference)
|
||||||
type_test(const int&, boost::call_traits<const int&>::const_reference)
|
type_test(const int&, boost::call_traits<const int&>::const_reference)
|
||||||
type_test(const int&, boost::call_traits<const int&>::param_type)
|
type_test(const int&, boost::call_traits<const int&>::param_type)
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
type_test(const int*, boost::call_traits<int[3]>::value_type)
|
type_test(const int*, boost::call_traits<int[3]>::value_type)
|
||||||
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
|
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
|
||||||
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
|
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
|
||||||
@@ -277,6 +260,11 @@ int main()
|
|||||||
type_test(const int(&)[3], boost::call_traits<const int[3]>::reference)
|
type_test(const int(&)[3], boost::call_traits<const int[3]>::reference)
|
||||||
type_test(const int(&)[3], boost::call_traits<const int[3]>::const_reference)
|
type_test(const int(&)[3], boost::call_traits<const int[3]>::const_reference)
|
||||||
type_test(const int*const, boost::call_traits<const int[3]>::param_type)
|
type_test(const int*const, boost::call_traits<const int[3]>::param_type)
|
||||||
|
#else
|
||||||
|
std::cout << "You're compiler does not support partial template instantiation, skipping 8 tests (8 errors)" << std::endl;
|
||||||
|
failures += 8;
|
||||||
|
test_count += 8;
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
|
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
|
||||||
failures += 20;
|
failures += 20;
|
||||||
@@ -339,7 +327,7 @@ struct call_traits_test<T, true>
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void call_traits_test<T, true>::assert_construct(boost::call_traits<T>::param_type val)
|
void call_traits_test<T, true>::assert_construct(typename boost::call_traits<T>::param_type val)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// this is to check that the call_traits assertions are valid:
|
// this is to check that the call_traits assertions are valid:
|
||||||
@@ -363,16 +351,16 @@ void call_traits_test<T, true>::assert_construct(boost::call_traits<T>::param_ty
|
|||||||
param_type p4(p);
|
param_type p4(p);
|
||||||
}
|
}
|
||||||
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
|
||||||
//
|
//
|
||||||
// now check call_traits assertions by instantiating call_traits_test:
|
// now check call_traits assertions by instantiating call_traits_test:
|
||||||
template struct call_traits_test<int>;
|
template struct call_traits_test<int>;
|
||||||
template struct call_traits_test<const int>;
|
template struct call_traits_test<const int>;
|
||||||
template struct call_traits_test<int*>;
|
template struct call_traits_test<int*>;
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
template struct call_traits_test<int&>;
|
template struct call_traits_test<int&>;
|
||||||
template struct call_traits_test<const int&>;
|
template struct call_traits_test<const int&>;
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
template struct call_traits_test<int[2], true>;
|
template struct call_traits_test<int[2], true>;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
148
cast.htm
148
cast.htm
@@ -1,148 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
<title>Header boost/cast.hpp Documentation</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
|
|
||||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
|
|
||||||
<a href="../../boost/cast.hpp">boost/cast.hpp</a></h1>
|
|
||||||
<h2><a name="Cast Functions">Cast Functions</a></h2>
|
|
||||||
<p>The <code>header <a href="../../boost/cast.hpp">boost/cast.hpp</a></code>
|
|
||||||
provides <a href="#Polymorphic_cast"><b>polymorphic_cast</b></a>, <a href="#Polymorphic_cast"><b>polymorphic_downcast</b></a>,
|
|
||||||
and <a href="#numeric_cast"><b>numeric_cast</b></a> template functions designed
|
|
||||||
to complement the C++ Standard's built-in casts.</p>
|
|
||||||
<p>The program <a href="cast_test.cpp">cast_test.cpp</a> can be used to
|
|
||||||
verify these function templates work as expected.</p>
|
|
||||||
<p><b>polymorphic_cast</b> was suggested by Bjarne Stroustrup in "The C++
|
|
||||||
Programming Language".<br>
|
|
||||||
<b>polymorphic_downcast</b> was contributed by <a href="../../people/dave_abrahams.htm">Dave
|
|
||||||
Abrahams</a>.<b><br>
|
|
||||||
numeric_cast</b> was contributed by <a href="../../people/kevlin_henney.htm">Kevlin
|
|
||||||
Henney</a>.</p>
|
|
||||||
<h3>Namespace synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>namespace boost {
|
|
||||||
namespace cast {
|
|
||||||
// all synopsis below included here
|
|
||||||
}
|
|
||||||
using ::boost::cast::polymorphic_cast;
|
|
||||||
using ::boost::cast::polymorphic_downcast;
|
|
||||||
using ::boost::cast::bad_numeric_cast;
|
|
||||||
using ::boost::cast::numeric_cast;
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3><a name="Polymorphic_cast">Polymorphic casts</a></h3>
|
|
||||||
<p>Pointers to polymorphic objects (objects of classes which define at least one
|
|
||||||
virtual function) are sometimes downcast or crosscast. Downcasting means
|
|
||||||
casting from a base class to a derived class. Crosscasting means casting
|
|
||||||
across an inheritance hierarchy diagram, such as from one base to the other in a
|
|
||||||
<b>Y</b> diagram hierarchy.</p>
|
|
||||||
<p>Such casts can be done with old-style casts, but this approach is never to be
|
|
||||||
recommended. Old-style casts are sorely lacking in type safety, suffer
|
|
||||||
poor readability, and are difficult to locate with search tools.</p>
|
|
||||||
<p>The C++ built-in <b>static_cast</b> can be used for efficiently downcasting
|
|
||||||
pointers to polymorphic objects, but provides no error detection for the case
|
|
||||||
where the pointer being cast actually points to the wrong derived class. The <b>polymorphic_downcast</b>
|
|
||||||
template retains the efficiency of <b>static_cast</b> for non-debug
|
|
||||||
compilations, but for debug compilations adds safety via an assert() that a <b>dynamic_cast</b>
|
|
||||||
succeeds. <b> </b></p>
|
|
||||||
<p>The C++ built-in <b>dynamic_cast</b> can be used for downcasts and crosscasts
|
|
||||||
of pointers to polymorphic objects, but error notification in the form of a
|
|
||||||
returned value of 0 is inconvenient to test, or worse yet, easy to forget to
|
|
||||||
test. The <b>polymorphic_cast</b> template performs a <b>dynamic_cast</b>,
|
|
||||||
and throws an exception if the <b>dynamic_cast</b> returns 0.</p>
|
|
||||||
<p>A <b>polymorphic_downcast</b> is preferred when debug-mode tests will cover
|
|
||||||
100% of the object types possibly cast and when non-debug-mode efficiency is an
|
|
||||||
issue. If these two conditions are not present, <b>polymorphic_cast</b> is
|
|
||||||
preferred. It must also be used for crosscasts. It does an assert(
|
|
||||||
dynamic_cast<Derived>(x) == x ) where x is the base pointer, ensuring that
|
|
||||||
not only is a non-zero pointer returned, but also that it correct in the
|
|
||||||
presence of multiple inheritance. .<b> Warning:</b>: Because <b>polymorphic_downcast</b>
|
|
||||||
uses assert(), it violates the One Definition Rule if NDEBUG is inconsistently
|
|
||||||
defined across translation units.</p>
|
|
||||||
<p>The C++ built-in <b>dynamic_cast</b> must be used to cast references rather
|
|
||||||
than pointers. It is also the only cast that can be used to check whether
|
|
||||||
a given interface is supported; in that case a return of 0 isn't an error
|
|
||||||
condition.</p>
|
|
||||||
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>template <class Derived, class Base>
|
|
||||||
inline Derived polymorphic_cast(Base* x);
|
|
||||||
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
|
|
||||||
// Returns: dynamic_cast<Derived>(x)
|
|
||||||
|
|
||||||
template <class Derived, class Base>
|
|
||||||
inline Derived polymorphic_downcast(Base* x);
|
|
||||||
// Effects: assert( dynamic_cast<Derived>(x) == x );
|
|
||||||
// Returns: static_cast<Derived>(x)</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>polymorphic_downcast example</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>#include <boost/cast.hpp>
|
|
||||||
...
|
|
||||||
class Fruit { public: virtual ~Fruit(){}; ... };
|
|
||||||
class Banana : public Fruit { ... };
|
|
||||||
...
|
|
||||||
void f( Fruit * fruit ) {
|
|
||||||
// ... logic which leads us to believe it is a Banana
|
|
||||||
Banana * banana = boost::polymorphic_downcast<Banana*>(fruit);
|
|
||||||
...</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3><a name="numeric_cast">numeric_cast</a></h3>
|
|
||||||
<p>A <b>static_cast</b>, <b>implicit_cast</b> or implicit conversion will not
|
|
||||||
detect failure to preserve range for numeric casts. The <b>numeric_cast</b>
|
|
||||||
template function are similar to <b>static_cast</b> and certain (dubious)
|
|
||||||
implicit conversions in this respect, except that they detect loss of numeric
|
|
||||||
range. An exception is thrown when a runtime value preservation check fails.</p>
|
|
||||||
<p>The requirements on the argument and result types are:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul>
|
|
||||||
<li>Both argument and result types are CopyConstructible [20.1.3].</li>
|
|
||||||
<li>Both argument and result types are Numeric, defined by <code>std::numeric_limits<>::is_specialized</code>
|
|
||||||
being true.</li>
|
|
||||||
<li>The argument can be converted to the result type using <b>static_cast</b>.</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>class bad_numeric_cast : public std::bad_cast {...};
|
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
|
||||||
inline Target numeric_cast(Source arg);
|
|
||||||
// Throws: bad_numeric_cast unless, in converting arg from Source to Target,
|
|
||||||
// there is no loss of negative range, and no underflow, and no
|
|
||||||
// overflow, as determined by std::numeric_limits
|
|
||||||
// Returns: static_cast<Target>(arg)</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast example</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>#include <boost/cast.hpp>
|
|
||||||
using namespace boost::cast;
|
|
||||||
|
|
||||||
void ariane(double vx)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
unsigned short dx = numeric_cast<unsigned short>(vx);
|
|
||||||
...
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast rationale</h3>
|
|
||||||
<p>The form of the throws condition is specified so that != is not a required
|
|
||||||
operation.</p>
|
|
||||||
<hr>
|
|
||||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan
|
|
||||||
-->28 June, 2000<!--webbot bot="Timestamp" endspan i-checksum="19846"
|
|
||||||
--></p>
|
|
||||||
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
|
|
||||||
distribute this document is granted provided this copyright notice appears in
|
|
||||||
all copies. This document is provided "as is" without express or
|
|
||||||
implied warranty, and with no claim as to its suitability for any purpose.</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
149
cast_test.cpp
149
cast_test.cpp
@@ -1,149 +0,0 @@
|
|||||||
// boost utility cast test program -----------------------------------------//
|
|
||||||
|
|
||||||
// (C) Copyright boost.org 1999. 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.
|
|
||||||
|
|
||||||
// See http://www.boost.org for most recent version including documentation.
|
|
||||||
|
|
||||||
// Revision History
|
|
||||||
// 28 Jun 00 implicit_cast removed (Beman Dawes)
|
|
||||||
// 30 Aug 99 value_cast replaced by numeric_cast
|
|
||||||
// 3 Aug 99 Initial Version
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <climits>
|
|
||||||
#include <limits>
|
|
||||||
#include <boost/cast.hpp>
|
|
||||||
|
|
||||||
# if SCHAR_MAX == LONG_MAX
|
|
||||||
# error "This test program doesn't work if SCHAR_MAX == LONG_MAX"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
using namespace boost;
|
|
||||||
using std::cout;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
struct Base
|
|
||||||
{
|
|
||||||
virtual char kind() { return 'B'; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Base2
|
|
||||||
{
|
|
||||||
virtual char kind2() { return '2'; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Derived : public Base, Base2
|
|
||||||
{
|
|
||||||
virtual char kind() { return 'D'; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main( int argc, char * argv[] )
|
|
||||||
{
|
|
||||||
cout << "Usage: test_casts [n], where n omitted or is:\n"
|
|
||||||
" 1 = execute #1 assert failure (#ifndef NDEBUG)\n"
|
|
||||||
" 2 = execute #2 assert failure (#ifndef NDEBUG)\n"
|
|
||||||
"Example: test_casts 2\n\n";
|
|
||||||
|
|
||||||
# ifdef NDEBUG
|
|
||||||
cout << "NDEBUG is defined\n";
|
|
||||||
# else
|
|
||||||
cout << "NDEBUG is not defined\n";
|
|
||||||
# endif
|
|
||||||
|
|
||||||
cout << "\nBeginning tests...\n";
|
|
||||||
|
|
||||||
// test polymorphic_cast ---------------------------------------------------//
|
|
||||||
|
|
||||||
// tests which should succeed
|
|
||||||
Base * base = new Derived;
|
|
||||||
Base2 * base2 = 0;
|
|
||||||
Derived * derived = 0;
|
|
||||||
derived = polymorphic_downcast<Derived*>( base ); // downcast
|
|
||||||
assert( derived->kind() == 'D' );
|
|
||||||
|
|
||||||
derived = 0;
|
|
||||||
derived = polymorphic_cast<Derived*>( base ); // downcast, throw on error
|
|
||||||
assert( derived->kind() == 'D' );
|
|
||||||
|
|
||||||
base2 = polymorphic_cast<Base2*>( base ); // crosscast
|
|
||||||
assert( base2->kind2() == '2' );
|
|
||||||
|
|
||||||
// tests which should result in errors being detected
|
|
||||||
int err_count = 0;
|
|
||||||
base = new Base;
|
|
||||||
|
|
||||||
if ( argc > 1 && *argv[1] == '1' )
|
|
||||||
{ derived = polymorphic_downcast<Derived*>( base ); } // #1 assert failure
|
|
||||||
|
|
||||||
bool caught_exception = false;
|
|
||||||
try { derived = polymorphic_cast<Derived*>( base ); }
|
|
||||||
catch (std::bad_cast)
|
|
||||||
{ cout<<"caught bad_cast\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
// the following is just so generated code can be inspected
|
|
||||||
if ( derived->kind() == 'B' ) ++err_count;
|
|
||||||
|
|
||||||
// test implicit_cast and numeric_cast -------------------------------------//
|
|
||||||
|
|
||||||
// tests which should succeed
|
|
||||||
long small_value = 1;
|
|
||||||
long small_negative_value = -1;
|
|
||||||
long large_value = std::numeric_limits<long>::max();
|
|
||||||
long large_negative_value = std::numeric_limits<long>::min();
|
|
||||||
signed char c = 0;
|
|
||||||
|
|
||||||
c = large_value; // see if compiler generates warning
|
|
||||||
|
|
||||||
c = numeric_cast<signed char>( small_value );
|
|
||||||
assert( c == 1 );
|
|
||||||
c = 0;
|
|
||||||
c = numeric_cast<signed char>( small_value );
|
|
||||||
assert( c == 1 );
|
|
||||||
c = 0;
|
|
||||||
c = numeric_cast<signed char>( small_negative_value );
|
|
||||||
assert( c == -1 );
|
|
||||||
|
|
||||||
// tests which should result in errors being detected
|
|
||||||
|
|
||||||
caught_exception = false;
|
|
||||||
try { c = numeric_cast<signed char>( large_value ); }
|
|
||||||
catch (bad_numeric_cast)
|
|
||||||
{ cout<<"caught bad_numeric_cast #1\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
|
|
||||||
caught_exception = false;
|
|
||||||
try { c = numeric_cast<signed char>( large_negative_value ); }
|
|
||||||
catch (bad_numeric_cast)
|
|
||||||
{ cout<<"caught bad_numeric_cast #2\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
|
|
||||||
unsigned long ul;
|
|
||||||
caught_exception = false;
|
|
||||||
try { ul = numeric_cast<unsigned long>( large_negative_value ); }
|
|
||||||
catch (bad_numeric_cast)
|
|
||||||
{ cout<<"caught bad_numeric_cast #3\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
|
|
||||||
caught_exception = false;
|
|
||||||
try { ul = numeric_cast<unsigned long>( small_negative_value ); }
|
|
||||||
catch (bad_numeric_cast)
|
|
||||||
{ cout<<"caught bad_numeric_cast #4\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
|
|
||||||
caught_exception = false;
|
|
||||||
try { numeric_cast<int>( std::numeric_limits<double>::max() ); }
|
|
||||||
catch (bad_numeric_cast)
|
|
||||||
{ cout<<"caught bad_numeric_cast #5\n"; caught_exception = true; }
|
|
||||||
if ( !caught_exception ) ++err_count;
|
|
||||||
|
|
||||||
cout << err_count << " errors detected\nTest "
|
|
||||||
<< (err_count==0 ? "passed\n" : "failed\n");
|
|
||||||
return err_count;
|
|
||||||
} // main
|
|
@@ -5,43 +5,19 @@
|
|||||||
// in all copies. This software is provided "as is" without express or implied
|
// 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.
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
|
||||||
|
// standalone test program for <boost/compressed_pair.hpp>
|
||||||
|
// Revised 03 Oct 2000:
|
||||||
|
// Enabled tests for VC6.
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <boost/compressed_pair.hpp>
|
#include <boost/compressed_pair.hpp>
|
||||||
|
#include "type_traits_test.hpp"
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
|
||||||
#pragma option -w-ccc -w-rch -w-eff -w-aus
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// define tests here
|
|
||||||
unsigned failures = 0;
|
|
||||||
unsigned test_count = 0;
|
|
||||||
|
|
||||||
#define value_test(v, x) ++test_count;\
|
|
||||||
if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
|
||||||
#define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;
|
|
||||||
|
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(boost::is_same<v, x>::value == false){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << typeid(boost::is_same<v, x>).name() << "::value is false" << std::endl; }
|
|
||||||
#else
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(typeid(v) != typeid(x)){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct empty_POD_UDT{};
|
struct empty_POD_UDT{};
|
||||||
struct empty_UDT
|
struct empty_UDT
|
||||||
{
|
{
|
||||||
@@ -65,6 +41,23 @@ template <> struct is_POD<empty_POD_UDT>
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct non_empty1
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
non_empty1() : i(1){}
|
||||||
|
non_empty1(int v) : i(v){}
|
||||||
|
friend bool operator==(const non_empty1& a, const non_empty1& b)
|
||||||
|
{ return a.i == b.i; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct non_empty2
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
non_empty2() : i(3){}
|
||||||
|
non_empty2(int v) : i(v){}
|
||||||
|
friend bool operator==(const non_empty2& a, const non_empty2& b)
|
||||||
|
{ return a.i == b.i; }
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -79,15 +72,22 @@ int main()
|
|||||||
assert(cp1b.second() == 1.3);
|
assert(cp1b.second() == 1.3);
|
||||||
assert(cp1.first() == 2);
|
assert(cp1.first() == 2);
|
||||||
assert(cp1.second() == 2.3);
|
assert(cp1.second() == 2.3);
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
compressed_pair<non_empty1, non_empty2> cp1c(non_empty1(9));
|
||||||
|
assert(cp1c.second() == non_empty2());
|
||||||
|
assert(cp1c.first() == non_empty1(9));
|
||||||
|
compressed_pair<non_empty1, non_empty2> cp1d(non_empty2(9));
|
||||||
|
assert(cp1d.second() == non_empty2(9));
|
||||||
|
assert(cp1d.first() == non_empty1());
|
||||||
compressed_pair<empty_UDT, int> cp2(2);
|
compressed_pair<empty_UDT, int> cp2(2);
|
||||||
assert(cp2.second() == 2);
|
assert(cp2.second() == 2);
|
||||||
#endif
|
|
||||||
compressed_pair<int, empty_UDT> cp3(1);
|
compressed_pair<int, empty_UDT> cp3(1);
|
||||||
assert(cp3.first() ==1);
|
assert(cp3.first() ==1);
|
||||||
compressed_pair<empty_UDT, empty_UDT> cp4;
|
compressed_pair<empty_UDT, empty_UDT> cp4;
|
||||||
compressed_pair<empty_UDT, empty_POD_UDT> cp5;
|
compressed_pair<empty_UDT, empty_POD_UDT> cp5;
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
compressed_pair<int, empty_UDT> cp9(empty_UDT());
|
||||||
|
compressed_pair<int, empty_UDT> cp10(1);
|
||||||
|
assert(cp10.first() == 1);
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
compressed_pair<int&, int&> cp6(i,i);
|
compressed_pair<int&, int&> cp6(i,i);
|
||||||
assert(cp6.first() == i);
|
assert(cp6.first() == i);
|
||||||
@@ -128,21 +128,25 @@ template class boost::compressed_pair<empty_UDT, empty_POD_UDT>;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
#ifndef __MWERKS__
|
||||||
//
|
//
|
||||||
// now some for which only a few specific members can be instantiated,
|
// now some for which only a few specific members can be instantiated,
|
||||||
// first references:
|
// first references:
|
||||||
template double& compressed_pair<double, int&>::first();
|
template double& compressed_pair<double, int&>::first();
|
||||||
template int& compressed_pair<double, int&>::second();
|
template int& compressed_pair<double, int&>::second();
|
||||||
|
#if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 95))
|
||||||
template compressed_pair<double, int&>::compressed_pair(int&);
|
template compressed_pair<double, int&>::compressed_pair(int&);
|
||||||
|
#endif
|
||||||
template compressed_pair<double, int&>::compressed_pair(call_traits<double>::param_type,int&);
|
template compressed_pair<double, int&>::compressed_pair(call_traits<double>::param_type,int&);
|
||||||
//
|
//
|
||||||
// and then arrays:
|
// and then arrays:
|
||||||
#ifndef __MWERKS__
|
|
||||||
#ifndef __BORLANDC__
|
#ifndef __BORLANDC__
|
||||||
template call_traits<int[2]>::reference compressed_pair<double, int[2]>::second();
|
template call_traits<int[2]>::reference compressed_pair<double, int[2]>::second();
|
||||||
#endif
|
#endif
|
||||||
template call_traits<double>::reference compressed_pair<double, int[2]>::first();
|
template call_traits<double>::reference compressed_pair<double, int[2]>::first();
|
||||||
template compressed_pair<double, int[2]>::compressed_pair(const double&);
|
#if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 95))
|
||||||
|
template compressed_pair<double, int[2]>::compressed_pair(call_traits<double>::param_type);
|
||||||
|
#endif
|
||||||
template compressed_pair<double, int[2]>::compressed_pair();
|
template compressed_pair<double, int[2]>::compressed_pair();
|
||||||
#endif // __MWERKS__
|
#endif // __MWERKS__
|
||||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
@@ -150,4 +154,3 @@ template compressed_pair<double, int[2]>::compressed_pair();
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
// See http://www.boost.org for most recent version including documentation.
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
// call_traits: defines typedefs for function usage
|
||||||
|
// (see libs/utility/call_traits.htm)
|
||||||
|
|
||||||
/* Release notes:
|
/* Release notes:
|
||||||
23rd July 2000:
|
23rd July 2000:
|
||||||
Fixed array specialization. (JM)
|
Fixed array specialization. (JM)
|
||||||
@@ -73,7 +76,7 @@ struct call_traits<T&>
|
|||||||
typedef T& param_type; // hh removed const
|
typedef T& param_type; // hh removed const
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x550)
|
#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x551)
|
||||||
// these are illegal specialisations; cv-qualifies applied to
|
// these are illegal specialisations; cv-qualifies applied to
|
||||||
// references have no effect according to [8.3.2p1],
|
// references have no effect according to [8.3.2p1],
|
||||||
// C++ Builder requires them though as it treats cv-qualified
|
// C++ Builder requires them though as it treats cv-qualified
|
||||||
|
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
// See http://www.boost.org for most recent version including documentation.
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
// compressed_pair: pair that "compresses" empty members
|
||||||
|
// (see libs/utility/compressed_pair.htm)
|
||||||
//
|
//
|
||||||
// JM changes 25 Jan 2000:
|
// JM changes 25 Jan 2000:
|
||||||
// Removed default arguments from compressed_pair_switch to get
|
// Removed default arguments from compressed_pair_switch to get
|
||||||
@@ -73,7 +75,9 @@ namespace details
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline void cp_swap(T& t1, T& t2)
|
inline void cp_swap(T& t1, T& t2)
|
||||||
{
|
{
|
||||||
|
#ifndef __GNUC__
|
||||||
using std::swap;
|
using std::swap;
|
||||||
|
#endif
|
||||||
swap(t1, t2);
|
swap(t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,16 @@
|
|||||||
// See http://www.boost.org for most recent version including documentation.
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
//
|
//
|
||||||
// Crippled version for crippled compilers:
|
// Crippled version for crippled compilers:
|
||||||
|
// see libs/utility/call_traits.htm
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/* Release notes:
|
||||||
|
01st October 2000:
|
||||||
|
Fixed call_traits on VC6, using "poor man's partial specialisation",
|
||||||
|
using ideas taken from "Generative programming" by Krzysztof Czarnecki
|
||||||
|
& Ulrich Eisenecker.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef BOOST_OB_CALL_TRAITS_HPP
|
#ifndef BOOST_OB_CALL_TRAITS_HPP
|
||||||
#define BOOST_OB_CALL_TRAITS_HPP
|
#define BOOST_OB_CALL_TRAITS_HPP
|
||||||
|
|
||||||
@@ -21,6 +30,85 @@
|
|||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
|
//
|
||||||
|
// use member templates to emulate
|
||||||
|
// partial specialisation:
|
||||||
|
//
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct standard_call_traits
|
||||||
|
{
|
||||||
|
typedef T value_type;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef const T& const_reference;
|
||||||
|
typedef const T& param_type;
|
||||||
|
};
|
||||||
|
template <class T>
|
||||||
|
struct simple_call_traits
|
||||||
|
{
|
||||||
|
typedef T value_type;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef const T& const_reference;
|
||||||
|
typedef const T param_type;
|
||||||
|
};
|
||||||
|
template <class T>
|
||||||
|
struct reference_call_traits
|
||||||
|
{
|
||||||
|
typedef T value_type;
|
||||||
|
typedef T reference;
|
||||||
|
typedef T const_reference;
|
||||||
|
typedef T param_type;
|
||||||
|
};
|
||||||
|
template <bool simple, bool reference>
|
||||||
|
struct call_traits_chooser
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef standard_call_traits<T> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct call_traits_chooser<true, false>
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef simple_call_traits<T> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct call_traits_chooser<false, true>
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef reference_call_traits<T> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
template <typename T>
|
||||||
|
struct call_traits
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef detail::call_traits_chooser<(is_pointer<T>::value || is_arithmetic<T>::value) && sizeof(T) <= sizeof(void*), is_reference<T>::value> chooser;
|
||||||
|
typedef typename chooser::template rebind<T> bound_type;
|
||||||
|
typedef typename bound_type::type call_traits_type;
|
||||||
|
public:
|
||||||
|
typedef typename call_traits_type::value_type value_type;
|
||||||
|
typedef typename call_traits_type::reference reference;
|
||||||
|
typedef typename call_traits_type::const_reference const_reference;
|
||||||
|
typedef typename call_traits_type::param_type param_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
// sorry call_traits is completely non-functional
|
||||||
|
// blame your broken compiler:
|
||||||
|
//
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct call_traits
|
struct call_traits
|
||||||
{
|
{
|
||||||
@@ -30,6 +118,8 @@ struct call_traits
|
|||||||
typedef const T& param_type;
|
typedef const T& param_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // member templates
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BOOST_OB_CALL_TRAITS_HPP
|
#endif // BOOST_OB_CALL_TRAITS_HPP
|
||||||
|
@@ -5,8 +5,13 @@
|
|||||||
// warranty, and with no claim as to its suitability for any purpose.
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
|
||||||
// See http://www.boost.org for most recent version including documentation.
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
// see libs/utility/compressed_pair.hpp
|
||||||
//
|
//
|
||||||
/* Release notes:
|
/* Release notes:
|
||||||
|
07 Oct 2000:
|
||||||
|
Added better single argument constructor support.
|
||||||
|
03 Oct 2000:
|
||||||
|
Added VC6 support (JM).
|
||||||
23rd July 2000:
|
23rd July 2000:
|
||||||
Additional comments added. (JM)
|
Additional comments added. (JM)
|
||||||
Jan 2000:
|
Jan 2000:
|
||||||
@@ -28,6 +33,386 @@
|
|||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
|
//
|
||||||
|
// use member templates to emulate
|
||||||
|
// partial specialisation. Note that due to
|
||||||
|
// problems with overload resolution with VC6
|
||||||
|
// each of the compressed_pair versions that follow
|
||||||
|
// have one template single-argument constructor
|
||||||
|
// in place of two specific constructors:
|
||||||
|
//
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template <class A, class T1, class T2>
|
||||||
|
struct best_convertion_traits
|
||||||
|
{
|
||||||
|
typedef char one;
|
||||||
|
typedef char (&two)[2];
|
||||||
|
static A a;
|
||||||
|
static one test(T1);
|
||||||
|
static two test(T2);
|
||||||
|
|
||||||
|
enum { value = sizeof(test(a)) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int>
|
||||||
|
struct init_one;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct init_one<1>
|
||||||
|
{
|
||||||
|
template <class A, class T1, class T2>
|
||||||
|
static void init(const A& a, T1* p1, T2*)
|
||||||
|
{
|
||||||
|
*p1 = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct init_one<2>
|
||||||
|
{
|
||||||
|
template <class A, class T1, class T2>
|
||||||
|
static void init(const A& a, T1*, T2* p2)
|
||||||
|
{
|
||||||
|
*p2 = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// T1 != T2, both non-empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_0
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T1 _first;
|
||||||
|
T2 _second;
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_0() : _first(), _second() {}
|
||||||
|
compressed_pair_0(first_param_type x, second_param_type y) : _first(x), _second(y) {}
|
||||||
|
template <class A>
|
||||||
|
explicit compressed_pair_0(const A& val)
|
||||||
|
{
|
||||||
|
init_one<best_convertion_traits<A, T1, T2>::value>::init(val, &_first, &_second);
|
||||||
|
}
|
||||||
|
compressed_pair_0(const compressed_pair_0<T1,T2>& x)
|
||||||
|
: _first(x._first), _second(x._second) {}
|
||||||
|
|
||||||
|
first_reference first() { return _first; }
|
||||||
|
first_const_reference first() const { return _first; }
|
||||||
|
|
||||||
|
second_reference second() { return _second; }
|
||||||
|
second_const_reference second() const { return _second; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_0& y)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(_first, y._first);
|
||||||
|
swap(_second, y._second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// T1 != T2, T2 empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_1 : T2
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T1 _first;
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_1() : T2(), _first() {}
|
||||||
|
compressed_pair_1(first_param_type x, second_param_type y) : T2(y), _first(x) {}
|
||||||
|
template <class A>
|
||||||
|
explicit compressed_pair_1(const A& val)
|
||||||
|
{
|
||||||
|
init_one<best_convertion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this));
|
||||||
|
}
|
||||||
|
compressed_pair_1(const compressed_pair_1<T1,T2>& x)
|
||||||
|
: T2(x), _first(x._first) {}
|
||||||
|
|
||||||
|
first_reference first() { return _first; }
|
||||||
|
first_const_reference first() const { return _first; }
|
||||||
|
|
||||||
|
second_reference second() { return *this; }
|
||||||
|
second_const_reference second() const { return *this; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_1& y)
|
||||||
|
{
|
||||||
|
// no need to swap empty base class:
|
||||||
|
using std::swap;
|
||||||
|
swap(_first, y._first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// T1 != T2, T1 empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_2 : T1
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T2 _second;
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_2() : T1(), _second() {}
|
||||||
|
compressed_pair_2(first_param_type x, second_param_type y) : T1(x), _second(y) {}
|
||||||
|
template <class A>
|
||||||
|
explicit compressed_pair_2(const A& val)
|
||||||
|
{
|
||||||
|
init_one<best_convertion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second);
|
||||||
|
}
|
||||||
|
compressed_pair_2(const compressed_pair_2<T1,T2>& x)
|
||||||
|
: T1(x), _second(x._second) {}
|
||||||
|
|
||||||
|
first_reference first() { return *this; }
|
||||||
|
first_const_reference first() const { return *this; }
|
||||||
|
|
||||||
|
second_reference second() { return _second; }
|
||||||
|
second_const_reference second() const { return _second; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_2& y)
|
||||||
|
{
|
||||||
|
// no need to swap empty base class:
|
||||||
|
using std::swap;
|
||||||
|
swap(_second, y._second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// T1 != T2, both empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_3 : T1, T2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_3() : T1(), T2() {}
|
||||||
|
compressed_pair_3(first_param_type x, second_param_type y) : T1(x), T2(y) {}
|
||||||
|
template <class A>
|
||||||
|
explicit compressed_pair_3(const A& val)
|
||||||
|
{
|
||||||
|
init_one<best_convertion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this));
|
||||||
|
}
|
||||||
|
compressed_pair_3(const compressed_pair_3<T1,T2>& x)
|
||||||
|
: T1(x), T2(x) {}
|
||||||
|
|
||||||
|
first_reference first() { return *this; }
|
||||||
|
first_const_reference first() const { return *this; }
|
||||||
|
|
||||||
|
second_reference second() { return *this; }
|
||||||
|
second_const_reference second() const { return *this; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_3& y)
|
||||||
|
{
|
||||||
|
// no need to swap empty base classes:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// T1 == T2, and empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_4 : T1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_4() : T1() {}
|
||||||
|
compressed_pair_4(first_param_type x, second_param_type) : T1(x) {}
|
||||||
|
// only one single argument constructor since T1 == T2
|
||||||
|
explicit compressed_pair_4(first_param_type x) : T1(x) {}
|
||||||
|
compressed_pair_4(const compressed_pair_4& x)
|
||||||
|
: T1(x){}
|
||||||
|
|
||||||
|
first_reference first() { return *this; }
|
||||||
|
first_const_reference first() const { return *this; }
|
||||||
|
|
||||||
|
second_reference second() { return *this; }
|
||||||
|
second_const_reference second() const { return *this; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_4& y)
|
||||||
|
{
|
||||||
|
// no need to swap empty base classes:
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// T1 == T2, not empty
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair_5
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T1 _first;
|
||||||
|
T2 _second;
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair_5() : _first(), _second() {}
|
||||||
|
compressed_pair_5(first_param_type x, second_param_type y) : _first(x), _second(y) {}
|
||||||
|
// only one single argument constructor since T1 == T2
|
||||||
|
explicit compressed_pair_5(first_param_type x) : _first(x), _second() {}
|
||||||
|
|
||||||
|
first_reference first() { return _first; }
|
||||||
|
first_const_reference first() const { return _first; }
|
||||||
|
|
||||||
|
second_reference second() { return _second; }
|
||||||
|
second_const_reference second() const { return _second; }
|
||||||
|
|
||||||
|
void swap(compressed_pair_5& y)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap(_first, y._first);
|
||||||
|
swap(_second, y._second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool e1, bool e2, bool same>
|
||||||
|
struct compressed_pair_chooser
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_0<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct compressed_pair_chooser<false, true, false>
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_1<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct compressed_pair_chooser<true, false, false>
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_2<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct compressed_pair_chooser<true, true, false>
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_3<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct compressed_pair_chooser<true, true, true>
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_4<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct compressed_pair_chooser<false, false, true>
|
||||||
|
{
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct rebind
|
||||||
|
{
|
||||||
|
typedef compressed_pair_5<T1, T2> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T1, class T2>
|
||||||
|
struct compressed_pair_traits
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef compressed_pair_chooser<is_empty<T1>::value, is_empty<T2>::value, is_same<T1,T2>::value> chooser;
|
||||||
|
typedef typename chooser::template rebind<T1, T2> bound_type;
|
||||||
|
public:
|
||||||
|
typedef typename bound_type::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <class T1, class T2>
|
||||||
|
class compressed_pair : public detail::compressed_pair_traits<T1, T2>::type
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef typename detail::compressed_pair_traits<T1, T2>::type base_type;
|
||||||
|
public:
|
||||||
|
typedef T1 first_type;
|
||||||
|
typedef T2 second_type;
|
||||||
|
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||||
|
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||||
|
typedef typename call_traits<first_type>::reference first_reference;
|
||||||
|
typedef typename call_traits<second_type>::reference second_reference;
|
||||||
|
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||||
|
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||||
|
|
||||||
|
compressed_pair() : base_type() {}
|
||||||
|
compressed_pair(first_param_type x, second_param_type y) : base_type(x, y) {}
|
||||||
|
template <class A>
|
||||||
|
explicit compressed_pair(const A& x) : base_type(x){}
|
||||||
|
|
||||||
|
first_reference first() { return base_type::first(); }
|
||||||
|
first_const_reference first() const { return base_type::first(); }
|
||||||
|
|
||||||
|
second_reference second() { return base_type::second(); }
|
||||||
|
second_const_reference second() const { return base_type::second(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T1, class T2>
|
||||||
|
inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||||
|
{
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// no partial specialisation, no member templates:
|
||||||
|
|
||||||
template <class T1, class T2>
|
template <class T1, class T2>
|
||||||
class compressed_pair
|
class compressed_pair
|
||||||
@@ -71,7 +456,11 @@ inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
|||||||
x.swap(y);
|
x.swap(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#endif // BOOST_OB_COMPRESSED_PAIR_HPP
|
#endif // BOOST_OB_COMPRESSED_PAIR_HPP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -69,6 +69,10 @@
|
|||||||
#pragma set woff 1234
|
#pragma set woff 1234
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
# pragma warning( disable : 4284 ) // complaint about return type of
|
||||||
|
#endif // operator-> not begin a UDT
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <cstddef> // for size_t
|
#include <cstddef> // for size_t
|
||||||
|
#include <utility> // for std::pair
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
@@ -63,6 +64,32 @@ namespace boost
|
|||||||
const noncopyable& operator=( const noncopyable& );
|
const noncopyable& operator=( const noncopyable& );
|
||||||
}; // noncopyable
|
}; // noncopyable
|
||||||
|
|
||||||
|
// class tied -------------------------------------------------------//
|
||||||
|
|
||||||
|
// A helper for conveniently assigning the two values from a pair
|
||||||
|
// into separate variables. The idea for this comes from Jaakko J<>rvi's
|
||||||
|
// Binder/Lambda Library.
|
||||||
|
|
||||||
|
// Constributed by Jeremy Siek
|
||||||
|
|
||||||
|
template <class A, class B>
|
||||||
|
class tied {
|
||||||
|
public:
|
||||||
|
inline tied(A& a, B& b) : _a(a), _b(b) { }
|
||||||
|
template <class U, class V>
|
||||||
|
inline tied& operator=(const std::pair<U,V>& p) {
|
||||||
|
_a = p.first;
|
||||||
|
_b = p.second;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
A& _a;
|
||||||
|
B& _b;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class A, class B>
|
||||||
|
inline tied<A,B> tie(A& a, B& b) { return tied<A,B>(a, b); }
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
#endif // BOOST_UTILITY_HPP
|
#endif // BOOST_UTILITY_HPP
|
||||||
|
72
index.htm
72
index.htm
@@ -1,72 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
<title>Boost Utility Library</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
|
|
||||||
<table border="1" cellpadding="2" bgcolor="#007F7F">
|
|
||||||
<tr>
|
|
||||||
<td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td>
|
|
||||||
<td><a href="../../index.htm"><font color="#FFFFFF" size="4" face="Arial">Home</font></a></td>
|
|
||||||
<td><a href="../../libraries.htm"><font color="#FFFFFF" size="4" face="Arial">Libraries</font></a></td>
|
|
||||||
<td><a href="../../people.htm"><font color="#FFFFFF" size="4" face="Arial">People</font></a></td>
|
|
||||||
<td><a href="../../more/faq.htm"><font color="#FFFFFF" size="4" face="Arial">FAQ</font></a></td>
|
|
||||||
<td><a href="../../more/index.htm"><font color="#FFFFFF" size="4" face="Arial">More</font></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1>Boost Utility Library</h1>
|
|
||||||
<table border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b><i>Header</i></b></td>
|
|
||||||
<td><b><i>Contents</i></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/utility.hpp"><code>boost/utility.hpp<br>
|
|
||||||
</code></a><a href="utility.htm">[Documentation]</a></td>
|
|
||||||
<td>Class <b>noncopyable</b> plus <b>next()</b> and <b>prior()</b> template
|
|
||||||
functions.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/cast.hpp"><code>boost/cast.hpp</code></a><br>
|
|
||||||
<a href="cast.htm">[Documentation]</a></td>
|
|
||||||
<td><b>polymorphic_cast</b>, <b>implicit_cast</b>, and <b>numeric_cast</b>
|
|
||||||
function templates.
|
|
||||||
<p><i>[Beta.]</i></p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/operators.hpp">boost/operators.hpp</a><br>
|
|
||||||
<a href="operators.htm">[Documentation]</a></td>
|
|
||||||
<td>Templates <b>equality_comparable</b>, <b>less_than_comparable</b>, <b>addable</b>,
|
|
||||||
and the like ease the task of defining comparison and arithmetic
|
|
||||||
operators, and iterators.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a><br>
|
|
||||||
[<a href="type_traits.htm">Documentation</a>]</td>
|
|
||||||
<td>Template classes that describe the fundamental properties of a type. [<a href="c++_type_traits.htm">DDJ
|
|
||||||
Article "C++ type traits"</a>]</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/detail/call_traits.hpp">boost/call_traits.hpp</a><br>
|
|
||||||
[<a href="call_traits.htm">Documentation</a>]</td>
|
|
||||||
<td>Template class call_traits<T>, that defines types used for passing
|
|
||||||
parameters to and from a proceedure.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><a href="../../boost/detail/compressed_pair.hpp">boost/compressed_pair.hpp</a><br>
|
|
||||||
[<a href="compressed_pair.htm">Documentation</a>]</td>
|
|
||||||
<td>Template class compressed_pait<T1, T2> which pairs two values
|
|
||||||
using the empty member optimisation where appropriate.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->27 July 2000<!--webbot bot="Timestamp" endspan i-checksum="18770" --></p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
47
iterator_adaptor_examples.cpp
Normal file
47
iterator_adaptor_examples.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// (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 <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/pending/iterator_adaptors.hpp>
|
||||||
|
#include <boost/pending/integer_range.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
// This is a simple example of using the transform_iterators class to
|
||||||
|
// generate iterators that multiply the value returned by dereferencing
|
||||||
|
// the iterator. In this case we are multiplying by 2.
|
||||||
|
// Would be cooler to use lambda library in this example.
|
||||||
|
|
||||||
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
|
||||||
|
typedef std::binder1st< std::multiplies<int> > Function;
|
||||||
|
typedef boost::transform_iterator<Function, int*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, int>
|
||||||
|
>::type doubling_iterator;
|
||||||
|
|
||||||
|
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||||
|
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
|
||||||
|
|
||||||
|
std::cout << "multiplying the array by 2:" << std::endl;
|
||||||
|
while (i != i_end)
|
||||||
|
std::cout << *i++ << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Here is an example of counting from 0 to 5 using the integer_range class.
|
||||||
|
|
||||||
|
boost::integer_range<int> r(0,5);
|
||||||
|
|
||||||
|
std::cout << "counting to from 0 to 4:" << std::endl;
|
||||||
|
std::copy(r.begin(), r.end(), std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
176
iterator_adaptor_test.cpp
Normal file
176
iterator_adaptor_test.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// Demonstrate and test boost/operators.hpp on std::iterators -------------//
|
||||||
|
|
||||||
|
// (C) Copyright Jeremy Siek 1999. 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.
|
||||||
|
|
||||||
|
// See http://www.boost.org for most recent version including documentation.
|
||||||
|
|
||||||
|
// Revision History
|
||||||
|
// 13 Jun 00 Added const version of the iterator tests (Jeremy Siek)
|
||||||
|
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <boost/pending/iterator_adaptors.hpp>
|
||||||
|
#include <boost/pending/iterator_tests.hpp>
|
||||||
|
#include <boost/pending/integer_range.hpp>
|
||||||
|
|
||||||
|
struct my_iterator_tag : public std::random_access_iterator_tag { };
|
||||||
|
|
||||||
|
|
||||||
|
using boost::dummyT;
|
||||||
|
|
||||||
|
struct my_iter_traits {
|
||||||
|
typedef dummyT value_type;
|
||||||
|
typedef dummyT* pointer;
|
||||||
|
typedef dummyT& reference;
|
||||||
|
typedef my_iterator_tag iterator_category;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct my_const_iter_traits {
|
||||||
|
typedef dummyT value_type;
|
||||||
|
typedef const dummyT* pointer;
|
||||||
|
typedef const dummyT& reference;
|
||||||
|
typedef my_iterator_tag iterator_category;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::iterator_adaptors
|
||||||
|
<dummyT*, const dummyT*,
|
||||||
|
my_iter_traits, my_const_iter_traits> My;
|
||||||
|
|
||||||
|
struct mult_functor {
|
||||||
|
typedef int result_type;
|
||||||
|
typedef int argument_type;
|
||||||
|
// Functors used with transform_iterator must be
|
||||||
|
// DefaultConstructible, as the transform_iterator must be
|
||||||
|
// DefaultConstructible to satisfy the requirements for
|
||||||
|
// TrivialIterator.
|
||||||
|
mult_functor() { }
|
||||||
|
mult_functor(int aa) : a(aa) { }
|
||||||
|
int operator()(int b) const { return a * b; }
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Pair>
|
||||||
|
struct select1st_
|
||||||
|
: public std::unary_function<Pair, typename Pair::first_type>
|
||||||
|
{
|
||||||
|
const typename Pair::first_type& operator()(const Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
typename Pair::first_type& operator()(Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
|
||||||
|
dummyT(3), dummyT(4), dummyT(5) };
|
||||||
|
const int N = sizeof(array)/sizeof(dummyT);
|
||||||
|
|
||||||
|
// sanity check, if this doesn't pass the test is buggy
|
||||||
|
boost::random_access_iterator_test(array,N,array);
|
||||||
|
|
||||||
|
// Test the iterator_adaptors
|
||||||
|
{
|
||||||
|
My::iterator i = array;
|
||||||
|
boost::random_access_iterator_test(i, N, array);
|
||||||
|
|
||||||
|
My::const_iterator j = array;
|
||||||
|
boost::random_access_iterator_test(j, N, array);
|
||||||
|
boost::const_nonconst_iterator_test(i, ++j);
|
||||||
|
}
|
||||||
|
// Test transform_iterator
|
||||||
|
{
|
||||||
|
int x[N], y[N];
|
||||||
|
for (int k = 0; k < N; ++k)
|
||||||
|
x[k] = k;
|
||||||
|
std::copy(x, x + N, y);
|
||||||
|
|
||||||
|
for (int k2 = 0; k2 < N; ++k2)
|
||||||
|
x[k2] = x[k2] * 2;
|
||||||
|
|
||||||
|
boost::transform_iterator<mult_functor, int*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag,int> >::type
|
||||||
|
i(y, mult_functor(2));
|
||||||
|
boost::random_access_iterator_test(i, N, x);
|
||||||
|
}
|
||||||
|
// Test indirect_iterators
|
||||||
|
{
|
||||||
|
dummyT* ptr[N];
|
||||||
|
for (int k = 0; k < N; ++k)
|
||||||
|
ptr[k] = array + k;
|
||||||
|
typedef boost::indirect_iterators<dummyT**, dummyT*, const dummyT*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, dummyT*>,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, dummyT>,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, const dummyT>
|
||||||
|
> Indirect;
|
||||||
|
Indirect::iterator i = ptr;
|
||||||
|
boost::random_access_iterator_test(i, N, array);
|
||||||
|
|
||||||
|
Indirect::const_iterator j = ptr;
|
||||||
|
boost::random_access_iterator_test(j, N, array);
|
||||||
|
|
||||||
|
boost::const_nonconst_iterator_test(i, ++j);
|
||||||
|
}
|
||||||
|
// Test projection_iterators
|
||||||
|
{
|
||||||
|
typedef std::pair<dummyT,dummyT> Pair;
|
||||||
|
Pair pair_array[N];
|
||||||
|
for (int k = 0; k < N; ++k)
|
||||||
|
pair_array[k].first = array[k];
|
||||||
|
|
||||||
|
typedef boost::projection_iterators<select1st_<Pair>,
|
||||||
|
Pair*, const Pair*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, Pair>,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, const Pair>
|
||||||
|
> Projection;
|
||||||
|
|
||||||
|
Projection::iterator i = pair_array;
|
||||||
|
boost::random_access_iterator_test(i, N, array);
|
||||||
|
|
||||||
|
Projection::const_iterator j = pair_array;
|
||||||
|
boost::random_access_iterator_test(j, N, array);
|
||||||
|
|
||||||
|
boost::const_nonconst_iterator_test(i, ++j);
|
||||||
|
}
|
||||||
|
// Test reverse_iterators
|
||||||
|
{
|
||||||
|
dummyT reversed[N];
|
||||||
|
std::copy(array, array + N, reversed);
|
||||||
|
std::reverse(reversed, reversed + N);
|
||||||
|
|
||||||
|
typedef boost::reverse_iterators<dummyT*, const dummyT*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag,dummyT>,
|
||||||
|
boost::iterator<std::random_access_iterator_tag,const dummyT>
|
||||||
|
> Reverse;
|
||||||
|
Reverse::iterator i = reversed + N;
|
||||||
|
boost::random_access_iterator_test(i, N, array);
|
||||||
|
|
||||||
|
Reverse::const_iterator j = reversed + N;
|
||||||
|
boost::random_access_iterator_test(j, N, array);
|
||||||
|
|
||||||
|
boost::const_nonconst_iterator_test(i, ++j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test integer_range's iterators
|
||||||
|
{
|
||||||
|
int int_array[] = { 0, 1, 2, 3, 4, 5 };
|
||||||
|
boost::integer_range<int> r(0, 5);
|
||||||
|
boost::random_access_iterator_test(r.begin(), r.size(), int_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "test successful " << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
809
iterator_adaptors.htm
Normal file
809
iterator_adaptors.htm
Normal file
@@ -0,0 +1,809 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||||
|
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||||
|
<title>Header boost/iterator_adaptors.hpp Documentation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body bgcolor="#FFFFFF" text="#000000">
|
||||||
|
|
||||||
|
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||||
|
align="center" width="277" height="86">
|
||||||
|
|
||||||
|
<h1>Header
|
||||||
|
<a href="../../boost/pending/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||||
|
and
|
||||||
|
<a href="../../boost/pending/integer_range.hpp">boost/integer_range.hpp</a></h1>
|
||||||
|
|
||||||
|
<p>The file <tt>boost/iterator_adaptors.hpp</tt>
|
||||||
|
includes the main <tt>iterator_adaptors</tt> class and several other classes
|
||||||
|
for constructing commonly used iterator adaptors.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#iterator_adaptors"><tt>iterator_adaptors</tt></a>.
|
||||||
|
<li><a href="#iterator_adaptor"><tt>iterator_adaptor</tt></a>.
|
||||||
|
<li><a href="#transform_iterator"><tt>transform_iterator</tt></a>
|
||||||
|
<li><a href="#indirect_iterators"><tt>Indirect Iterator Adaptors</tt></a>
|
||||||
|
<li><a href="#projection_iterators"><tt>Projection Iterator Adaptors</tt></a>
|
||||||
|
<li><a href="#reverse_iterators"><tt>reverse_iterators</tt></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The file <tt>boost/integer_range.hpp</tt> includes a class that
|
||||||
|
uses iterator adaptors to create an iterator that increments over a
|
||||||
|
range of integers. The file also includes a "container" type
|
||||||
|
that creates a container-interface for the range of integers.
|
||||||
|
<ul>
|
||||||
|
<li><a href="#integer_range"><tt>integer_range</tt></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- put in something about Andrei Alexandrescu's contribution? -->
|
||||||
|
|
||||||
|
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
|
||||||
|
Abrahams</a> started the library, coming up with the idea to use
|
||||||
|
policy classes and how to handle the const/non-const iterator
|
||||||
|
interactions. He also contributed the <tt>indirect_iterators</tt> and
|
||||||
|
<tt>reverse_iterators</tt> classes.<br>
|
||||||
|
|
||||||
|
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||||
|
contributed <tt>transform_iterator</tt>, <tt>integer_range</tt>,
|
||||||
|
and this documentation.<br>
|
||||||
|
|
||||||
|
<a href="http://www.boost.org/people/john_potter.htm">John Potter</a>
|
||||||
|
contributed <tt>indirect_iterator</tt> and <tt>projection_iterator</tt>
|
||||||
|
and made some simplifications to <tt>iterator_adaptor</tt>.
|
||||||
|
|
||||||
|
<h3><a name="iterator_adaptors">The Iterator Adaptors Class</a></h3>
|
||||||
|
|
||||||
|
Implementing standard conforming iterators is a non-trivial task.
|
||||||
|
There are some fine-points such as iterator/const_iterator
|
||||||
|
interactions and there are the myriad of operators that should be
|
||||||
|
implemented but are easily forgotten such as
|
||||||
|
<tt>operator->()</tt>. The purpose of the
|
||||||
|
<tt>iterator_adaptors</tt> class is to make it easier to implement an
|
||||||
|
iterator class, and even easier to extend and adapt existing iterator
|
||||||
|
types. The <tt>iterator_adaptors</tt> class itself is not an adaptor
|
||||||
|
class but a <i>type generator</i>. It generates a pair of adaptor classes,
|
||||||
|
one class for the mutable iterator and one class for the const
|
||||||
|
iterator. The definition of the <tt>iterator_adaptors</tt> class is as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator,
|
||||||
|
class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>,
|
||||||
|
class Policies = default_iterator_policies>
|
||||||
|
struct iterator_adaptors
|
||||||
|
{
|
||||||
|
typedef ... iterator;
|
||||||
|
typedef ... const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>The <tt>Iterator</tt> and <tt>ConstIterator</tt> template parameters
|
||||||
|
are the iterator types that you want to adapt. The <tt>Traits</tt> and
|
||||||
|
<tt>ConstTraits</tt> must be iterator traits classes. The traits
|
||||||
|
parameters default to the specialization of the
|
||||||
|
<tt>std::iterator_traits</tt> class for the adapted iterators. If you
|
||||||
|
want the traits for your new iterator adaptor (<tt>value_type</tt>,
|
||||||
|
<tt>iterator_category</tt>, etc.) to be the same as the adapted
|
||||||
|
iterator then use the default, otherwise create your own traits
|
||||||
|
classes and pass them in <a href="#1">[1]</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<p>The <tt>Policies</tt> class that you pass in will become the heart of
|
||||||
|
the iterator adaptor. The policy class determines how your new adaptor
|
||||||
|
class will behave. The <tt>Policies</tt> class must implement 3, 4, or
|
||||||
|
7 of the core iterator operations depending on whether you wish the
|
||||||
|
new iterator adaptor class to be a
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/ForwardIterator.html">
|
||||||
|
ForwardIterator</a>,
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
|
||||||
|
BidirectionalIterator</a>, or <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||||
|
RandomAccessIterator</a>. Make sure that the
|
||||||
|
<tt>iterator_category</tt> type of the traits class you pass in
|
||||||
|
matches the category of iterator that you want to create. The default
|
||||||
|
policy class, <tt>default_iterator_policies</tt>, implements all 7 of
|
||||||
|
the core operations in the usual way. If you wish to create an
|
||||||
|
iterator adaptor that only changes a few of the iterator's behaviors,
|
||||||
|
then you can have your new policy class inherit from
|
||||||
|
<tt>default_iterator_policies</tt> to avoid retyping the usual
|
||||||
|
behaviours. You should also look at <tt>default_iterator_policies</tt>
|
||||||
|
as the "boiler-plate" for your own policy classes. The
|
||||||
|
following is definition of the <tt>default_iterator_policies</tt>
|
||||||
|
class:
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct default_iterator_policies
|
||||||
|
{
|
||||||
|
// required for a ForwardIterator
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return *x; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
static void increment(Iterator& x)
|
||||||
|
{ ++x; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool equal(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x == y; }
|
||||||
|
|
||||||
|
// required for a BidirectionalIterator
|
||||||
|
template <class Iterator>
|
||||||
|
static void decrement(Iterator& x)
|
||||||
|
{ --x; }
|
||||||
|
|
||||||
|
// required for a RandomAccessIterator
|
||||||
|
template <class Iterator, class DifferenceType>
|
||||||
|
static void advance(Iterator& x, DifferenceType n)
|
||||||
|
{ x += n; }
|
||||||
|
|
||||||
|
template <class Difference, class Iterator1, class Iterator2>
|
||||||
|
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||||
|
{ return y - x; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool less(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x < y; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The generated iterator adaptor types will have the following
|
||||||
|
constructors.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
<i>iterator</i>(const Iterator& i, const Policies& p = Policies())
|
||||||
|
|
||||||
|
<i>const_iterator</i>(const ConstIterator& i, const Policies& p = Policies())
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<h3><a name="iterator_adaptor">The Iterator Adaptor Class</a></h3>
|
||||||
|
|
||||||
|
This is the class used inside of the <tt>iterator_adaptors</tt> type
|
||||||
|
generator. Use this class directly (instead of using
|
||||||
|
<tt>iterator_adaptors</tt>) when you are interested in creating only
|
||||||
|
one of the iterator types (either const or non-const) or when there is
|
||||||
|
no difference between the const and non-const versions of the iterator
|
||||||
|
type (often this is because there is only a const (read-only) version
|
||||||
|
of the iterator, as is the case for <tt>std::set</tt>'s iterators).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator,
|
||||||
|
class Policies = default_iterator_policies,
|
||||||
|
class Traits = std::iterator_traits<Iterator> >
|
||||||
|
struct iterator_adaptor;
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Next we will look at some iterator adaptors that are examples of how
|
||||||
|
to use the iterator adaptors class, and that are useful iterator
|
||||||
|
adaptors in their own right.
|
||||||
|
|
||||||
|
<h3><a name="transform_iterator">The Transform Iterator Class</a></h3>
|
||||||
|
|
||||||
|
It is often useful to automatically apply some function to the value
|
||||||
|
returned by dereferencing (<tt>operator*()</tt>) an iterator. The
|
||||||
|
<tt>transform_iterators</tt> class makes it easy to create an iterator
|
||||||
|
adaptor that does just that.
|
||||||
|
|
||||||
|
First let us consider what the <tt>Policies</tt> class for the transform
|
||||||
|
iterator should look like. We are only changing one of the iterator
|
||||||
|
behaviours, so we will inherit from
|
||||||
|
<tt>default_iterator_policies</tt>. In addition, we will need a
|
||||||
|
function object to apply, so we will have a template parameter and a
|
||||||
|
data member for the function object. The function will take one
|
||||||
|
argument (the dereferenced value) and we will need to know the
|
||||||
|
<tt>result_type</tt> of the function, so <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/AdaptableUnaryFunction.html">
|
||||||
|
AdaptableUnaryFunction</a> is the corrent concept to choose for the
|
||||||
|
function object type. Now for the heart of our iterator adaptor, we
|
||||||
|
implement the <tt>dereference</tt> method, applying the function
|
||||||
|
object to <tt>*i</tt>. The <tt>type<Reference></tt> class is
|
||||||
|
there to tell you what the reference type of the iterator is, which is
|
||||||
|
handy when writing generic iterator adaptors such as this one <a
|
||||||
|
href="#2">[2]</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction>
|
||||||
|
struct transform_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
transform_iterator_policies() { }
|
||||||
|
transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
|
||||||
|
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& i) const
|
||||||
|
{ return m_f(*i); }
|
||||||
|
|
||||||
|
AdaptableUnaryFunction m_f;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Next we need to create the traits class for our new iterator. In some
|
||||||
|
situations you may need to create a separate traits class for the
|
||||||
|
const and non-const iterator types, but here a single traits class
|
||||||
|
will do. The <tt>value_type</tt> and <tt>reference</tt> type of our
|
||||||
|
transform iterator will be the <tt>result_type</tt> of the function
|
||||||
|
object. The <tt>difference_type</tt> and <tt>iterator_category</tt>
|
||||||
|
will be the same as the adapted iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class IteratorTraits>
|
||||||
|
struct transform_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef typename IteratorTraits::difference_type difference_type;
|
||||||
|
typedef typename IteratorTraits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
The final step is to use the <tt>iterator_adaptor</tt> class to
|
||||||
|
construct our transform iterator. We will use the single iterator
|
||||||
|
adaptor version because we will not need to create both a mutable and
|
||||||
|
const version of the transform iterator. The transform iterator is
|
||||||
|
inherently a read-only iterator. The nicest way to package up our new
|
||||||
|
transform iterator is to create a type generator similar to
|
||||||
|
<tt>iterator_adaptor</tt>. The first template parameter will be the
|
||||||
|
type of the function object. The second parameter will be the adapted
|
||||||
|
iterator type. The third parameter is the trait class for
|
||||||
|
the adapted iterator. Inside the <tt>transform_iterators</tt> class
|
||||||
|
we use the <tt>transform_iterator_traits</tt> class defined above to
|
||||||
|
create the traits class for the new transform iterator. We then use
|
||||||
|
the <tt>iterator_adaptor</tt> class to extract the generated
|
||||||
|
iterator adaptor type.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction,
|
||||||
|
class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct transform_iterator
|
||||||
|
{
|
||||||
|
typedef transform_iterator_traits<AdaptableUnaryFunction,Traits>
|
||||||
|
TransTraits;
|
||||||
|
typedef iterator_adaptor<Iterator, TransTraits,
|
||||||
|
transform_iterator_policies<AdaptableUnaryFunction> >::type type;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following is a simple example of how to use the
|
||||||
|
<tt>transform_iterators</tt> class to iterate through a range of
|
||||||
|
numbers, multiplying each of them by 2 when they are dereferenced.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/iterator_adaptors.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
|
||||||
|
typedef std::binder1st< std::multiplies<int> > Function;
|
||||||
|
typedef boost::transform_iterator<Function, int*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, int>
|
||||||
|
>::type doubling_iterator;
|
||||||
|
|
||||||
|
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||||
|
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
|
||||||
|
|
||||||
|
std::cout << "multiplying the array by 2:" << std::endl;
|
||||||
|
while (i != i_end)
|
||||||
|
std::cout << *i++ << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="indirect_iterators">The Indirect Iterator Adaptors</a></h3>
|
||||||
|
|
||||||
|
It is not all that uncommon to create data structures that consist of
|
||||||
|
pointers to pointers. For such a structure it might be nice to have an
|
||||||
|
iterator that applies a double-dereference inside the
|
||||||
|
<tt>operator*()</tt>. The implementation of this is similar to the
|
||||||
|
<tt>transform_iterators</tt><a href="#3">[3]</a>. When talking about a
|
||||||
|
data structure of pointers to pointers (or more generally, iterators
|
||||||
|
to iterators), we call the first level iterators the <i>outer</i>
|
||||||
|
iterators and the second level iterators the <i>inner</i>
|
||||||
|
iterators. For example, if the outer iterator type is <tt>T**</tt>
|
||||||
|
then the inner iterator type is <tt>T*</tt>.
|
||||||
|
|
||||||
|
To implement the indirect adaptors, we first create a policies class
|
||||||
|
which does a double-dereference in the <tt>dereference()</tt> method.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct indirect_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return **x; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
We then create a traits class, including a template parameter for both
|
||||||
|
the inner and outer iterators and traits classes. The
|
||||||
|
<tt>difference_type</tt> and <tt>iterator_category</tt> come from the
|
||||||
|
outer iterator, while the <tt>value_type</tt>, <tt>pointer</tt>, and
|
||||||
|
<tt>reference</tt> types come from the inner iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class OuterIterator, class InnerIterator,
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_traits
|
||||||
|
{
|
||||||
|
typedef typename OuterTraits::difference_type difference_type;
|
||||||
|
typedef typename InnerTraits::value_type value_type;
|
||||||
|
typedef typename InnerTraits::pointer pointer;
|
||||||
|
typedef typename InnerTraits::reference reference;
|
||||||
|
typedef typename OuterTraits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Lastly we wrap this up in two type generators:
|
||||||
|
<tt>indirect_iterator</tt> for creating a single indirect iterator
|
||||||
|
type, and <tt>indirect_iterators</tt> for creating an const/non-const
|
||||||
|
pair of indirect iterator types. We use the <tt>iterator_adaptor</tt>
|
||||||
|
and <tt>iterator_adaptors</tt> classes here to do most of the work.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class OuterIterator, class InnerIterator,
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_iterator
|
||||||
|
{
|
||||||
|
typedef iterator_adaptor<OuterIterator,
|
||||||
|
indirect_iterator_policies,
|
||||||
|
indirect_traits<OuterIterator, InnerIterator,
|
||||||
|
OuterTraits, InnerTraits>
|
||||||
|
> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class OuterIterator, // Mutable or Immutable, does not matter
|
||||||
|
class InnerIterator, // Mutable
|
||||||
|
class ConstInnerIterator, // Immutable
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>,
|
||||||
|
class ConstInnerTraits = std::iterator_traits<ConstInnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_iterators
|
||||||
|
{
|
||||||
|
typedef iterator_adaptors<OuterIterator, OuterIterator,
|
||||||
|
indirect_traits<OuterIterator, InnerIterator,
|
||||||
|
OuterTraits, InnerTraits>,
|
||||||
|
indirect_traits<OuterIterator, ConstInnerIterator,
|
||||||
|
OuterTraits, ConstInnerTraits>,
|
||||||
|
indirect_iterator_policies
|
||||||
|
> Adaptors;
|
||||||
|
typedef typename Adaptors::iterator iterator;
|
||||||
|
typedef typename Adaptors::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="projection_iterators">The Projection Iterator Adaptors</a></h3>
|
||||||
|
|
||||||
|
The projection iterator adaptor is very similar to the transform
|
||||||
|
iterator, except for a subtle difference in the return type: the
|
||||||
|
tranform iterator returns the result of the unary function by value,
|
||||||
|
whereas the projection iterator returns the result by reference.
|
||||||
|
Therefore, these two adaptors cater to different kinds of unary
|
||||||
|
functions. Transform iterator caters to functions that create new
|
||||||
|
objects, whereas projection iterator caters to a function that somehow
|
||||||
|
obtains a reference to an object that already exists. An example of a
|
||||||
|
unary function that is suitable for use with the projection adaptor is
|
||||||
|
<tt>select1st_</tt>:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Pair>
|
||||||
|
struct select1st_
|
||||||
|
: public std::unary_function<Pair, typename Pair::first_type>
|
||||||
|
{
|
||||||
|
const typename Pair::first_type& operator()(const Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
typename Pair::first_type& operator()(Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
The implementation of projection iterator is as follows. First, the
|
||||||
|
policies class is the same as the transform iterator's policies class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction>
|
||||||
|
struct projection_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
projection_iterator_policies() { }
|
||||||
|
projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
|
||||||
|
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference (type<Reference>, Iterator const& iter) const {
|
||||||
|
return m_f(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdaptableUnaryFunction m_f;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Next we have two traits classes. We use <tt>value_type&</tt> for the
|
||||||
|
reference type of the mutable projection iterator, and <tt>const
|
||||||
|
value_type&</tt> for the immutable projection iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class Traits>
|
||||||
|
struct projection_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type& reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef typename Traits::difference_type difference_type;
|
||||||
|
typedef typename Traits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Traits>
|
||||||
|
struct const_projection_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type const& reference;
|
||||||
|
typedef value_type const* pointer;
|
||||||
|
typedef typename Traits::difference_type difference_type;
|
||||||
|
typedef typename Traits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
And to finish up, we create three generator classes that
|
||||||
|
use <tt>iterator_adaptor</tt> to create the projection iterator
|
||||||
|
types. The class <tt>projection_iterator</tt> creates a mutable
|
||||||
|
projection iterator type. The class <tt>const_projection_iterator</tt>
|
||||||
|
creates an immutable projection iterator type, and
|
||||||
|
<tt>projection_iterators</tt> creates both mutable and immutable
|
||||||
|
projection iterator types.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct projection_iterator {
|
||||||
|
typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
|
||||||
|
Projection_Traits;
|
||||||
|
typedef iterator_adaptor<Iterator,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction>,
|
||||||
|
Projection_Traits> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct const_projection_iterator {
|
||||||
|
typedef const_projection_iterator_traits<AdaptableUnaryFunction,
|
||||||
|
Traits> Projection_Traits;
|
||||||
|
typedef iterator_adaptor<Iterator,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction>,
|
||||||
|
Projection_Traits> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator, class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>
|
||||||
|
>
|
||||||
|
struct projection_iterators {
|
||||||
|
typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
|
||||||
|
Projection_Traits;
|
||||||
|
typedef const_projection_iterator_traits<AdaptableUnaryFunction,
|
||||||
|
ConstTraits> Const_Projection_Traits;
|
||||||
|
typedef iterator_adaptors<Iterator, ConstIterator,
|
||||||
|
Projection_Traits, Const_Projection_Traits,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction> > Adaptors;
|
||||||
|
typedef typename Adaptors::iterator iterator;
|
||||||
|
typedef typename Adaptors::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="reverse_iterators">The Reverse Iterators Class</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Yes, there is already a <tt>reverse_iterator</tt> adaptor class
|
||||||
|
defined in the C++ Standard, but using the <tt>iterator_adaptors</tt>
|
||||||
|
class we can re-implement this classic adaptor in a more succinct and
|
||||||
|
elegant fashion. Also, this makes for a good example of using
|
||||||
|
<tt>iterator_adaptors</tt> that is in familiar territory.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The first step is to create the <tt>Policies</tt> class. As in the
|
||||||
|
<tt>std::reverse_iterator</tt> class, we need to flip all the
|
||||||
|
operations of the iterator. Increment will become decrement, advancing
|
||||||
|
by <tt>n</tt> will become retreating by <tt>n</tt>, etc.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct reverse_iterator_policies
|
||||||
|
{
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return *boost::prior(x); }
|
||||||
|
// this is equivalent to { Iterator tmp = x; return *--tmp; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
void increment(Iterator& x) const
|
||||||
|
{ --x; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
void decrement(Iterator& x) const
|
||||||
|
{ ++x; }
|
||||||
|
|
||||||
|
template <class Iterator, class DifferenceType>
|
||||||
|
void advance(Iterator& x, DifferenceType n) const
|
||||||
|
{ x -= n; }
|
||||||
|
|
||||||
|
template <class Difference, class Iterator1, class Iterator2>
|
||||||
|
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x - y; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool equal(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x == y; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool less(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return y < x; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Since the traits of the reverse iterator adaptor will be the same as
|
||||||
|
the adapted iterator's traits, we do not need to create new traits
|
||||||
|
classes as was the case for <tt>transform_iterator</tt>. We can skip to
|
||||||
|
the final stage of creating a type generator class for our reverse
|
||||||
|
iterators using the <tt>iterator_adaptor</tt> class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator, class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>
|
||||||
|
>
|
||||||
|
struct reverse_iterators
|
||||||
|
{
|
||||||
|
typedef iterator_adaptors<Iterator,ConstIterator,Traits,ConstTraits,
|
||||||
|
reverse_iterator_policies> Adaptor;
|
||||||
|
typedef typename Adaptor::iterator iterator;
|
||||||
|
typedef typename Adaptor::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
A typical use of the <tt>reverse_iterators</tt> class is in
|
||||||
|
user-defined container types. You can use the
|
||||||
|
<tt>reverse_iterators</tt> class to generate the reverse iterators for
|
||||||
|
your container.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
class my_container {
|
||||||
|
...
|
||||||
|
typedef ... iterator;
|
||||||
|
typedef ... const_iterator;
|
||||||
|
|
||||||
|
typedef reverse_iterators<iterator, const_iterator> RevIters;
|
||||||
|
typedef typename RevIters::iterator reverse_iterator;
|
||||||
|
typedef typename RevIters::const_iterator const_reverse_iterator;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="integer_range">The Integer Range Class</a></h3>
|
||||||
|
|
||||||
|
The <tt>iterator_adaptors</tt> class can not only be used for adapting
|
||||||
|
iterators, but it can also be used to take a non-iterator type and use
|
||||||
|
it to build an iterator. An especially simple example of this is
|
||||||
|
turning an integer type into an iterator, a counting iterator. The
|
||||||
|
builtin integer types of C++ are almost iterators. They have
|
||||||
|
<tt>operator++()</tt>, <tt>operator--()</tt>, etc. The one operator
|
||||||
|
they are lacking is the <tt>operator*()</tt>, which we will want to
|
||||||
|
simply return the current value of the integer. The following few
|
||||||
|
lines of code implement the policy and traits class for the counting
|
||||||
|
iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class IntegerType>
|
||||||
|
struct counting_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
IntegerType dereference(type<IntegerType>, const IntegerType& i) const
|
||||||
|
{ return i; }
|
||||||
|
};
|
||||||
|
template <class IntegerType>
|
||||||
|
struct counting_iterator_traits {
|
||||||
|
typedef IntegerType value_type;
|
||||||
|
typedef IntegerType reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Typically we will want to count the integers in some range, so a nice
|
||||||
|
interface would be to have a fake container that represents the range
|
||||||
|
of integers. The following is the definition of such a class called
|
||||||
|
<tt>integer_range</tt>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class IntegerType>
|
||||||
|
struct integer_range {
|
||||||
|
typedef typename iterator_adaptor<IntegerType,
|
||||||
|
counting_iterator_traits<IntegerType>,
|
||||||
|
counting_iterator_policies >::type iterator;
|
||||||
|
typedef iterator const_iterator;
|
||||||
|
typedef IntegerType value_type;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef IntegerType reference;
|
||||||
|
typedef IntegerType* pointer;
|
||||||
|
typedef IntegerType size_type;
|
||||||
|
|
||||||
|
integer_range(IntegerType start, IntegerType finish)
|
||||||
|
: m_start(start), m_finish(finish) { }
|
||||||
|
|
||||||
|
iterator begin() const { return iterator(m_start); }
|
||||||
|
iterator end() const { return iterator(m_finish); }
|
||||||
|
size_type size() const { return m_finish - m_start; }
|
||||||
|
bool empty() const { return m_finish == m_start; }
|
||||||
|
void swap(integer_range& x) {
|
||||||
|
std::swap(m_start, x.m_start);
|
||||||
|
std::swap(m_finish, x.m_finish);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
IntegerType m_start, m_finish;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following is an example of how to use the
|
||||||
|
<tt>integer_range</tt> class to count from 0 to 4.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
boost::integer_range<int> r(0,5);
|
||||||
|
|
||||||
|
cout << "counting to from 0 to 4:" << endl;
|
||||||
|
std::copy(r.begin(), r.end(), ostream_iterator<int>(cout, " "));
|
||||||
|
cout << endl;
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<h3>Challenge</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There is an unlimited number of ways the the
|
||||||
|
<tt>iterator_adaptors</tt> class can be used to create iterators. One
|
||||||
|
interesting exercise would be to re-implement the iterators of
|
||||||
|
<tt>std::list</tt> and <tt>std::slist</tt> using
|
||||||
|
<tt>iterator_adaptors</tt>, where the adapted <tt>Iterator</tt> types
|
||||||
|
would be node pointers.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Notes</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="1">[1]</a>
|
||||||
|
If your compiler does not support partial specialization and hence
|
||||||
|
does not have a working <tt>std::iterator_traits</tt> class, you will
|
||||||
|
not be able to use the defaults and will need to supply your own
|
||||||
|
<tt>Traits</tt> and <tt>ConstTraits</tt> classes.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="2">[2]</a>
|
||||||
|
The reference type could also be obtained from
|
||||||
|
<tt>std::iterator_traits</tt>, but that is not portable on compilers
|
||||||
|
that do not support partial specialization.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="3">[3]</a>
|
||||||
|
It would have been more elegant to implement <tt>indirect_iterators</tt>
|
||||||
|
using <tt>transform_iterators</tt>, but for subtle reasons that would require
|
||||||
|
the use of <tt>boost::remove_cv</tt> which is not portable.
|
||||||
|
|
||||||
|
<h3>Implementation Notes</h3>
|
||||||
|
|
||||||
|
The code is somewhat complicated because there are three iterator
|
||||||
|
adaptor class: <tt>forward_iterator_adaptor</tt>,
|
||||||
|
<tt>bidirectional_iterator_adaptor</tt>, and
|
||||||
|
<tt>random_access_iterator_adaptor</tt>. The alternative would be to
|
||||||
|
just have one iterator adaptor equivalent to the
|
||||||
|
<tt>random_access_iterator_adaptor</tt>. The reason for going with
|
||||||
|
the three adaptors is that according to 14.5.3p5 in the C++ Standard,
|
||||||
|
friend functions defined inside a template class body are instantiated
|
||||||
|
when the template class is instantiated. This means that if we only
|
||||||
|
used the one iterator adaptor, then if the adapted iterator did not
|
||||||
|
meet all of the requirements for a
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||||
|
RandomAccessIterator</a> then a compiler error should occur. Many
|
||||||
|
current compilers in fact do not instantiate the friend functions
|
||||||
|
unless used, so we could get away with the one iterator adaptor in
|
||||||
|
most cases. However, out of respect for the standard this implementation
|
||||||
|
uses the three adaptors.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->27 Nov 2000<!--webbot bot="Timestamp" endspan i-checksum="15248" --></p>
|
||||||
|
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
|
||||||
|
modify, sell and distribute this document is granted provided this copyright
|
||||||
|
notice appears in all copies. This document is provided "as is"
|
||||||
|
without express or implied warranty, and with no claim as to its suitability for
|
||||||
|
any purpose.</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
|
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
|
||||||
<a href="../../boost/operators.hpp">boost/operators.hpp</a></h1>
|
<a href="../../boost/operators.hpp">boost/operators.hpp</a></h1>
|
||||||
<p>Header <a href="http://www.boost.org/boost/operators.hpp">boost/operators.hpp</a>
|
<p>Header <a href="../../boost/operators.hpp">boost/operators.hpp</a> supplies
|
||||||
supplies (in namespace boost) several sets of templates:</p>
|
(in namespace boost) several sets of templates:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#Arithmetic">Arithmetic operators</a>.
|
<li><a href="#Arithmetic">Arithmetic operators</a>.
|
||||||
<li><a href="#deref and helpers">Dereference operators and iterator helpers.</a></li>
|
<li><a href="#deref and helpers">Dereference operators and iterator helpers.</a></li>
|
||||||
@@ -43,10 +43,10 @@ additional operators, such as operator>, <=, >=, and +. <a href="
|
|||||||
forms</a> of the templates are also provided to allow interaction with other
|
forms</a> of the templates are also provided to allow interaction with other
|
||||||
types.</p>
|
types.</p>
|
||||||
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>
|
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>
|
||||||
started the library and contributed the arithmetic operators in <a href="http://www.boost.org/boost/operators.hpp">boost/operators.hpp</a>.<br>
|
started the library and contributed the arithmetic operators in <a href="../../boost/operators.hpp">boost/operators.hpp</a>.<br>
|
||||||
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||||
contributed the <a href="#deref and helpers">dereference operators and iterator
|
contributed the <a href="#deref and helpers">dereference operators and iterator
|
||||||
helpers</a> in <a href="http://www.boost.org/boost/operators.hpp">boost/operators.hpp</a>.<br>
|
helpers</a> in <a href="../../boost/operators.hpp">boost/operators.hpp</a>.<br>
|
||||||
<a href="http://www.boost.org/people/aleksey_gurtovoy.htm">Aleksey Gurtovoy</a>
|
<a href="http://www.boost.org/people/aleksey_gurtovoy.htm">Aleksey Gurtovoy</a>
|
||||||
contributed the code to support <a href="#chaining">base class chaining</a>
|
contributed the code to support <a href="#chaining">base class chaining</a>
|
||||||
while remaining backward-compatible with old versions of the library.<br>
|
while remaining backward-compatible with old versions of the library.<br>
|
||||||
@@ -60,7 +60,7 @@ x >= y,</code> and <code>x <= y</code>. Moreover, unless your class has
|
|||||||
really surprising behavior, some of these related operators can be defined in
|
really surprising behavior, some of these related operators can be defined in
|
||||||
terms of others (e.g. <code>x >= y <b><=></b> !(x < y)</code>).
|
terms of others (e.g. <code>x >= y <b><=></b> !(x < y)</code>).
|
||||||
Replicating this boilerplate for multiple classes is both tedious and
|
Replicating this boilerplate for multiple classes is both tedious and
|
||||||
error-prone. The <a href="http://www.boost.org/boost/operators.hpp">boost/operators.hpp</a>
|
error-prone. The <a href="../../boost/operators.hpp">boost/operators.hpp</a>
|
||||||
templates help by generating operators for you at namespace scope based on other
|
templates help by generating operators for you at namespace scope based on other
|
||||||
operators you've defined in your class.</p>
|
operators you've defined in your class.</p>
|
||||||
<a name="two_arg">
|
<a name="two_arg">
|
||||||
@@ -585,8 +585,7 @@ complicated than the old one, we think it's worth it to make the library more
|
|||||||
useful in real world. Alexy Gurtovoy contributed the code which supports the new
|
useful in real world. Alexy Gurtovoy contributed the code which supports the new
|
||||||
usage idiom while allowing the library remain backward-compatible.</p>
|
usage idiom while allowing the library remain backward-compatible.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->28 Jun 2000<!--webbot bot="Timestamp" endspan i-checksum="15058" -->
|
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->27 Sep 2000<!--webbot bot="Timestamp" endspan i-checksum="14936" --></p>
|
||||||
</p>
|
|
||||||
<p><EFBFBD> Copyright David Abrahams and Beman Dawes 1999-2000. Permission to copy,
|
<p><EFBFBD> Copyright David Abrahams and Beman Dawes 1999-2000. Permission to copy,
|
||||||
use, modify, sell and distribute this document is granted provided this
|
use, modify, sell and distribute this document is granted provided this
|
||||||
copyright notice appears in all copies. This document is provided "as
|
copyright notice appears in all copies. This document is provided "as
|
||||||
|
137
tie.html
Normal file
137
tie.html
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<HTML>
|
||||||
|
<!--
|
||||||
|
-- Copyright (c) Jeremy Siek, Lie-Quan Lee, and Andrew Lumsdaine 2000
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, distribute and sell this software
|
||||||
|
-- and its documentation for any purpose is hereby granted without fee,
|
||||||
|
-- provided that the above copyright notice appears in all copies and
|
||||||
|
-- that both that copyright notice and this permission notice appear
|
||||||
|
-- in supporting documentation. We make no
|
||||||
|
-- representations about the suitability of this software for any
|
||||||
|
-- purpose. It is provided "as is" without express or implied warranty.
|
||||||
|
-->
|
||||||
|
<Head>
|
||||||
|
<Title>Boost Tie</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:tie"></A>
|
||||||
|
<TT>tie</TT>
|
||||||
|
</H1>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
<PRE>
|
||||||
|
template <class A, class B>
|
||||||
|
tied<A,B> tie(A& a, B& b);
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
This is a utility function that makes it more convenient to work with
|
||||||
|
a function which returns a std::pair<>. The effect of the <TT>tie()</TT>
|
||||||
|
function is to allow the assignment of the two values of the pair to
|
||||||
|
two separate variables. The idea for this comes from Jaakko
|
||||||
|
Järvi's Binders [<A
|
||||||
|
HREF="../graph/doc/bibliography.html#jaakko_tuple_assign">1</A>].
|
||||||
|
|
||||||
|
<P>
|
||||||
|
|
||||||
|
<H3>Where Defined</H3>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
<a href="../../boost/utility.hpp"><TT>boost/utility.hpp</TT></a>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
|
||||||
|
<H3>Example</H3>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
An example of using the <TT>tie()</TT> function with the
|
||||||
|
<TT>vertices()</TT> function, which returns a pair of
|
||||||
|
type <TT>std::pair<vertex_iterator,vertex_iterator></TT>. The
|
||||||
|
pair of iterators is assigned to the iterator variables <TT>i</TT> and
|
||||||
|
<TT>end</TT>.
|
||||||
|
|
||||||
|
<P>
|
||||||
|
<PRE>
|
||||||
|
graph_traits< adjacency_list<> >::vertex_iterator i, end;
|
||||||
|
for(tie(i,end) = vertices(G); i != end; ++i)
|
||||||
|
// ...
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
Here is another example that uses <TT>tie()</TT> for handling operations with <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/set.html"><TT>std::set</TT></a>.
|
||||||
|
|
||||||
|
<P>
|
||||||
|
<PRE>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
{
|
||||||
|
typedef std::set<int> SetT;
|
||||||
|
SetT::iterator i, end;
|
||||||
|
bool inserted;
|
||||||
|
|
||||||
|
int vals[5] = { 5, 2, 4, 9, 1 };
|
||||||
|
SetT s(vals, vals + 5);
|
||||||
|
|
||||||
|
// Using tie() with a return value of pair<iterator,bool>
|
||||||
|
|
||||||
|
int new_vals[2] = { 3, 9 };
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k) {
|
||||||
|
boost::tie(i,inserted) = s.insert(new_vals[k]);
|
||||||
|
if (!inserted)
|
||||||
|
std::cout << *i << " was already in the set." << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << *i << " successfully inserted." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int* i, *end;
|
||||||
|
int vals[6] = { 5, 2, 4, 4, 9, 1 };
|
||||||
|
std::sort(vals, vals + 6);
|
||||||
|
|
||||||
|
// Using tie() with a return value of pair<iterator,iterator>
|
||||||
|
|
||||||
|
boost::tie(i,end) = std::equal_range(vals, vals + 6, 4);
|
||||||
|
std::cout << "There were " << std::distance(i,end)
|
||||||
|
<< " occurrences of " << *i << "." << std::endl;
|
||||||
|
// Footnote: of course one would normally just use std::count()
|
||||||
|
// to get this information, but that would spoil the example :)
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</PRE>
|
||||||
|
The output is:
|
||||||
|
<PRE>
|
||||||
|
3 successfully inserted.
|
||||||
|
9 was already in the set.
|
||||||
|
There were 2 occurrences of 4.
|
||||||
|
</PRE>
|
||||||
|
|
||||||
|
<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>)<br>
|
||||||
|
<A HREF=http://www.lsc.nd.edu/~llee1>Lie-Quan Lee</A>, Univ.of Notre Dame (<A HREF="mailto:llee1@lsc.nd.edu">llee1@lsc.nd.edu</A>)<br>
|
||||||
|
<A HREF=http://www.lsc.nd.edu/~lums>Andrew Lumsdaine</A>,
|
||||||
|
Univ.of Notre Dame (<A
|
||||||
|
HREF="mailto:lums@lsc.nd.edu">lums@lsc.nd.edu</A>)
|
||||||
|
</TD></TR></TABLE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
61
tie_example.cpp
Normal file
61
tie_example.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// (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 is an example demonstrating how to use the tie() function.
|
||||||
|
// The purpose of tie() is to make it easiery to deal with std::pair
|
||||||
|
// return values.
|
||||||
|
//
|
||||||
|
// Contributed by Jeremy Siek
|
||||||
|
//
|
||||||
|
// Sample output
|
||||||
|
//
|
||||||
|
// 3 successfully inserted.
|
||||||
|
// 9 was already in the set.
|
||||||
|
// There were 2 occurances of 4.
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
{
|
||||||
|
typedef std::set<int> SetT;
|
||||||
|
SetT::iterator i, end;
|
||||||
|
bool inserted;
|
||||||
|
|
||||||
|
int vals[5] = { 5, 2, 4, 9, 1 };
|
||||||
|
SetT s(vals, vals + 5);
|
||||||
|
|
||||||
|
// Using tie() with a return value of pair<iterator,bool>
|
||||||
|
|
||||||
|
int new_vals[2] = { 3, 9 };
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; ++k) {
|
||||||
|
boost::tie(i,inserted) = s.insert(new_vals[k]);
|
||||||
|
if (!inserted)
|
||||||
|
std::cout << *i << " was already in the set." << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << *i << " successfully inserted." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int* i, *end;
|
||||||
|
int vals[6] = { 5, 2, 4, 4, 9, 1 };
|
||||||
|
std::sort(vals, vals + 6);
|
||||||
|
|
||||||
|
// Using tie() with a return value of pair<iterator,iterator>
|
||||||
|
|
||||||
|
boost::tie(i,end) = std::equal_range(vals, vals + 6, 4);
|
||||||
|
std::cout << "There were " << std::distance(i,end)
|
||||||
|
<< " occurances of " << *i << "." << std::endl;
|
||||||
|
// Footnote: of course one would normally just use std::count()
|
||||||
|
// to get this information, but that would spoil the example :)
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
100
type_traits.htm
100
type_traits.htm
@@ -25,6 +25,7 @@ divided up into the following sections:</p>
|
|||||||
|
|
||||||
<pre><a href="#fop">Fundamental type operations</a>
|
<pre><a href="#fop">Fundamental type operations</a>
|
||||||
<a href="#fp">Fundamental type properties</a>
|
<a href="#fp">Fundamental type properties</a>
|
||||||
|
<a href="#misc">Miscellaneous</a>
|
||||||
<code> </code><a href="#cv">cv-Qualifiers</a>
|
<code> </code><a href="#cv">cv-Qualifiers</a>
|
||||||
<code> </code><a href="#ft">Fundamental Types</a>
|
<code> </code><a href="#ft">Fundamental Types</a>
|
||||||
<code> </code><a href="#ct">Compound Types</a>
|
<code> </code><a href="#ct">Compound Types</a>
|
||||||
@@ -37,7 +38,7 @@ divided up into the following sections:</p>
|
|||||||
<p>Usage: "class_name<T>::type" performs
|
<p>Usage: "class_name<T>::type" performs
|
||||||
indicated transformation on type T.</p>
|
indicated transformation on type T.</p>
|
||||||
|
|
||||||
<table border="1" cellpadding="7" cellspacing="1" width="624">
|
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><p align="center">Expression.</p>
|
<td valign="top" width="45%"><p align="center">Expression.</p>
|
||||||
</td>
|
</td>
|
||||||
@@ -108,40 +109,73 @@ indicated transformation on type T.</p>
|
|||||||
indicated property is true, false otherwise. (Note that class_name<T>::value
|
indicated property is true, false otherwise. (Note that class_name<T>::value
|
||||||
is always defined as a compile time constant).</p>
|
is always defined as a compile time constant).</p>
|
||||||
|
|
||||||
|
<h3><a name="misc"></a>Miscellaneous</h3>
|
||||||
|
|
||||||
|
<table border="1" cellspacing="1" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td width="37%"><p align="center">Expression</p>
|
||||||
|
</td>
|
||||||
|
<td width="36%"><p align="center">Description</p>
|
||||||
|
</td>
|
||||||
|
<td width="27%"><p align="center">Compiler</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="37%"><div align="center"><center><pre><code>is_same<T,U>::value</code></pre>
|
||||||
|
</center></div></td>
|
||||||
|
<td width="36%"><p align="center">True if T and U are the
|
||||||
|
same type.</p>
|
||||||
|
</td>
|
||||||
|
<td width="27%"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="37%"><div align="center"><center><pre>is_convertible<T,U>::value</pre>
|
||||||
|
</center></div></td>
|
||||||
|
<td width="36%"><p align="center">True if type T is
|
||||||
|
convertible to type U.</p>
|
||||||
|
</td>
|
||||||
|
<td width="27%"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="37%"><div align="center"><center><pre>alignment_of<T>::value</pre>
|
||||||
|
</center></div></td>
|
||||||
|
<td width="36%"><p align="center">An integral value
|
||||||
|
representing the minimum alignment requirements of type T
|
||||||
|
(strictly speaking defines a multiple of the type's
|
||||||
|
alignment requirement; for all compilers tested so far
|
||||||
|
however it does return the actual alignment).</p>
|
||||||
|
</td>
|
||||||
|
<td width="27%"> </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p> </p>
|
||||||
|
|
||||||
<h3><a name="cv"></a>cv-Qualifiers</h3>
|
<h3><a name="cv"></a>cv-Qualifiers</h3>
|
||||||
|
|
||||||
<p>The following classes determine what cv-qualifiers are present
|
<p>The following classes determine what cv-qualifiers are present
|
||||||
on a type (see 3.93).</p>
|
on a type (see 3.93).</p>
|
||||||
|
|
||||||
<table border="1" cellpadding="7" cellspacing="1" width="624">
|
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><p align="center">Expression.</p>
|
<td valign="top" width="37%"><p align="center">Expression.</p>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top" width="45%"><p align="center">Description.</p>
|
<td valign="top" width="37%"><p align="center">Description.</p>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top" width="33%"><p align="center">Compiler.</p>
|
<td valign="top" width="27%"><p align="center">Compiler.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><code>is_const<T>::value</code></td>
|
<td valign="top" width="37%"><code>is_const<T>::value</code></td>
|
||||||
<td valign="top" width="45%">True if type T is top-level
|
<td valign="top" width="37%">True if type T is top-level
|
||||||
const qualified.</td>
|
const qualified.</td>
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
<td valign="top" width="27%"> </td>
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><code>is_volatile<T>::value</code></td>
|
<td valign="top" width="37%"><code>is_volatile<T>::value</code></td>
|
||||||
<td valign="top" width="45%">True if type T is top-level
|
<td valign="top" width="37%">True if type T is top-level
|
||||||
volatile qualified.</td>
|
volatile qualified.</td>
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
<td valign="top" width="27%"> </td>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="45%"><code>is_same<T,U>::value</code></td>
|
|
||||||
<td valign="top" width="45%">True if T and U are the same
|
|
||||||
type.</td>
|
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -152,7 +186,7 @@ on a type (see 3.93).</p>
|
|||||||
<p>The following will only ever be true for cv-unqualified types;
|
<p>The following will only ever be true for cv-unqualified types;
|
||||||
these are closely based on the section 3.9 of the C++ Standard.</p>
|
these are closely based on the section 3.9 of the C++ Standard.</p>
|
||||||
|
|
||||||
<table border="1" cellpadding="7" cellspacing="1" width="624">
|
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><p align="center">Expression.</p>
|
<td valign="top" width="45%"><p align="center">Expression.</p>
|
||||||
</td>
|
</td>
|
||||||
@@ -291,7 +325,7 @@ these are closely based on the section 3.9 of the C++ Standard.</p>
|
|||||||
<p>The following will only ever be true for cv-unqualified types,
|
<p>The following will only ever be true for cv-unqualified types,
|
||||||
as defined by the Standard. </p>
|
as defined by the Standard. </p>
|
||||||
|
|
||||||
<table border="1" cellpadding="7" cellspacing="1" width="624">
|
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><p align="center">Expression</p>
|
<td valign="top" width="45%"><p align="center">Expression</p>
|
||||||
</td>
|
</td>
|
||||||
@@ -311,22 +345,19 @@ as defined by the Standard. </p>
|
|||||||
<td valign="top" width="45%">True if T is a regular
|
<td valign="top" width="45%">True if T is a regular
|
||||||
pointer type - including function pointers - but
|
pointer type - including function pointers - but
|
||||||
excluding pointers to member functions (3.9.2 p1 and 8.3.1).</td>
|
excluding pointers to member functions (3.9.2 p1 and 8.3.1).</td>
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
<td valign="top" width="33%"> </td>
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><code>is_member_pointer<T>::value</code></td>
|
<td valign="top" width="45%"><code>is_member_pointer<T>::value</code></td>
|
||||||
<td valign="top" width="45%">True if T is a pointer to a
|
<td valign="top" width="45%">True if T is a pointer to a
|
||||||
non-static class member (3.9.2 p1 and 8.3.1).</td>
|
non-static class member (3.9.2 p1 and 8.3.1).</td>
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
<td valign="top" width="33%"> </td>
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><code>is_reference<T>::value</code></td>
|
<td valign="top" width="45%"><code>is_reference<T>::value</code></td>
|
||||||
<td valign="top" width="45%">True if T is a reference
|
<td valign="top" width="45%">True if T is a reference
|
||||||
type (3.9.2 p1 and 8.3.2).</td>
|
type (3.9.2 p1 and 8.3.2).</td>
|
||||||
<td valign="top" width="33%"><p align="center">P</p>
|
<td valign="top" width="33%"> </td>
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><code>is_class<T>::value</code></td>
|
<td valign="top" width="45%"><code>is_class<T>::value</code></td>
|
||||||
@@ -365,7 +396,7 @@ as defined by the Standard. </p>
|
|||||||
is true then <code>class_name<cv-qualified-T>::value</code>
|
is true then <code>class_name<cv-qualified-T>::value</code>
|
||||||
will also be true.</p>
|
will also be true.</p>
|
||||||
|
|
||||||
<table border="1" cellpadding="7" cellspacing="1" width="624">
|
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top" width="45%"><p align="center">Expression</p>
|
<td valign="top" width="45%"><p align="center">Expression</p>
|
||||||
</td>
|
</td>
|
||||||
@@ -420,9 +451,10 @@ will also be true.</p>
|
|||||||
or class. If the compiler implements the "zero sized
|
or class. If the compiler implements the "zero sized
|
||||||
empty base classes" optimisation, then is_empty will
|
empty base classes" optimisation, then is_empty will
|
||||||
correctly guess whether T is empty. Relies upon is_class
|
correctly guess whether T is empty. Relies upon is_class
|
||||||
to determine whether T is a class type - as a result will
|
to determine whether T is a class type. Screens out enum
|
||||||
not compile when passed an enumerated type unless there
|
types by using is_convertible<T,int>, this means
|
||||||
is compiler support for is_enum.</td>
|
that empty classes that overload operator int(), will not
|
||||||
|
be classified as empty.</td>
|
||||||
<td valign="top" width="33%"><p align="center">PCD</p>
|
<td valign="top" width="33%"><p align="center">PCD</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -569,7 +601,7 @@ familiar standard library algorithms.</p>
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<p>Revised 08<sup>th</sup> March 2000</p>
|
<p>Revised 01 September 2000</p>
|
||||||
|
|
||||||
<p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify,
|
<p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify,
|
||||||
sell and distribute this document is granted provided this
|
sell and distribute this document is granted provided this
|
||||||
@@ -582,7 +614,7 @@ Hinnant and John Maddock.</p>
|
|||||||
|
|
||||||
<p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John
|
<p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John
|
||||||
Maddock</a>, the latest version of this file can be found at <a
|
Maddock</a>, the latest version of this file can be found at <a
|
||||||
href="http://www.boost.org">www.boost.org</a>, and the boost
|
href="http://www.boost.org/">www.boost.org</a>, and the boost
|
||||||
discussion list at <a href="http://www.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p>
|
discussion list at <a href="http://www.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -4,7 +4,11 @@
|
|||||||
// in all copies. This software is provided "as is" without express or implied
|
// 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.
|
// warranty, and with no claim as to its suitability for any purpose.
|
||||||
|
|
||||||
|
// standalone test program for <boost/type_traits.hpp>
|
||||||
|
|
||||||
/* Release notes:
|
/* Release notes:
|
||||||
|
31st July 2000:
|
||||||
|
Added extra tests for is_empty, is_convertible, alignment_of.
|
||||||
23rd July 2000:
|
23rd July 2000:
|
||||||
Removed all call_traits tests to call_traits_test.cpp
|
Removed all call_traits tests to call_traits_test.cpp
|
||||||
Removed all compressed_pair tests to compressed_pair_tests.cpp
|
Removed all compressed_pair tests to compressed_pair_tests.cpp
|
||||||
@@ -16,37 +20,11 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include <boost/type_traits.hpp>
|
#include <boost/type_traits.hpp>
|
||||||
|
#include <boost/utility.hpp>
|
||||||
|
#include "type_traits_test.hpp"
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
|
|
||||||
#ifdef __BORLANDC__
|
|
||||||
#pragma option -w-ccc -w-rch -w-eff -w-aus
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// define tests here
|
|
||||||
unsigned failures = 0;
|
|
||||||
unsigned test_count = 0;
|
|
||||||
|
|
||||||
#define value_test(v, x) ++test_count;\
|
|
||||||
if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
|
||||||
#define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;
|
|
||||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(is_same<v, x>::value == false){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << typeid(is_same<v, x>).name() << "::value is false" << std::endl; }
|
|
||||||
#else
|
|
||||||
#define type_test(v, x) ++test_count;\
|
|
||||||
if(typeid(v) != typeid(x)){\
|
|
||||||
++failures; \
|
|
||||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
|
||||||
std::cout << " expected type was " << #v << std::endl; \
|
|
||||||
std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Since there is no compiler support, we should specialize:
|
// Since there is no compiler support, we should specialize:
|
||||||
// is_enum for all enumerations (is_enum implies is_POD)
|
// is_enum for all enumerations (is_enum implies is_POD)
|
||||||
// is_union for all unions
|
// is_union for all unions
|
||||||
@@ -160,6 +138,50 @@ template <> struct is_POD<empty_POD_union_UDT>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class Base { };
|
||||||
|
|
||||||
|
class Deriverd : public Base { };
|
||||||
|
|
||||||
|
class NonDerived { };
|
||||||
|
|
||||||
|
enum enum1
|
||||||
|
{
|
||||||
|
one_,two_
|
||||||
|
};
|
||||||
|
|
||||||
|
enum enum2
|
||||||
|
{
|
||||||
|
three_,four_
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VB
|
||||||
|
{
|
||||||
|
virtual ~VB(){};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VD : VB
|
||||||
|
{
|
||||||
|
~VD(){};
|
||||||
|
};
|
||||||
|
//
|
||||||
|
// struct non_pointer:
|
||||||
|
// used to verify that is_pointer does not return
|
||||||
|
// true for class types that implement operator void*()
|
||||||
|
//
|
||||||
|
struct non_pointer
|
||||||
|
{
|
||||||
|
operator void*(){return this;}
|
||||||
|
};
|
||||||
|
//
|
||||||
|
// struct non_empty:
|
||||||
|
// used to verify that is_empty does not emit
|
||||||
|
// spurious warnings or errors.
|
||||||
|
//
|
||||||
|
struct non_empty : boost::noncopyable
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
// Steve: All comments that I (Steve Cleary) have added below are prefixed with
|
// Steve: All comments that I (Steve Cleary) have added below are prefixed with
|
||||||
// "Steve:" The failures that BCB4 has on the tests are due to Borland's
|
// "Steve:" The failures that BCB4 has on the tests are due to Borland's
|
||||||
// not considering cv-qual's as a part of the type -- they are considered
|
// not considering cv-qual's as a part of the type -- they are considered
|
||||||
@@ -216,6 +238,8 @@ int main()
|
|||||||
value_test(false, (is_same<int*, const int*>::value))
|
value_test(false, (is_same<int*, const int*>::value))
|
||||||
value_test(false, (is_same<int*, int*const>::value))
|
value_test(false, (is_same<int*, int*const>::value))
|
||||||
value_test(false, (is_same<int, int[2]>::value))
|
value_test(false, (is_same<int, int[2]>::value))
|
||||||
|
value_test(false, (is_same<int*, int[2]>::value))
|
||||||
|
value_test(false, (is_same<int[4], int[2]>::value))
|
||||||
|
|
||||||
value_test(false, is_const<int>::value)
|
value_test(false, is_const<int>::value)
|
||||||
value_test(true, is_const<const int>::value)
|
value_test(true, is_const<const int>::value)
|
||||||
@@ -359,9 +383,14 @@ int main()
|
|||||||
|
|
||||||
value_test(false, is_array<int>::value)
|
value_test(false, is_array<int>::value)
|
||||||
value_test(false, is_array<int*>::value)
|
value_test(false, is_array<int*>::value)
|
||||||
|
value_test(false, is_array<const int*>::value)
|
||||||
|
value_test(false, is_array<const volatile int*>::value)
|
||||||
value_test(true, is_array<int[2]>::value)
|
value_test(true, is_array<int[2]>::value)
|
||||||
|
value_test(true, is_array<const int[2]>::value)
|
||||||
|
value_test(true, is_array<const volatile int[2]>::value)
|
||||||
value_test(true, is_array<int[2][3]>::value)
|
value_test(true, is_array<int[2][3]>::value)
|
||||||
value_test(true, is_array<UDT[2]>::value)
|
value_test(true, is_array<UDT[2]>::value)
|
||||||
|
value_test(false, is_array<int(&)[2]>::value)
|
||||||
|
|
||||||
typedef void(*f1)();
|
typedef void(*f1)();
|
||||||
typedef int(*f2)(int);
|
typedef int(*f2)(int);
|
||||||
@@ -371,15 +400,28 @@ int main()
|
|||||||
typedef int (UDT::*mf3)(int);
|
typedef int (UDT::*mf3)(int);
|
||||||
typedef int (UDT::*mf4)(int, float);
|
typedef int (UDT::*mf4)(int, float);
|
||||||
|
|
||||||
|
value_test(false, is_const<f1>::value)
|
||||||
|
value_test(false, is_reference<f1>::value)
|
||||||
|
value_test(false, is_array<f1>::value)
|
||||||
value_test(false, is_pointer<int>::value)
|
value_test(false, is_pointer<int>::value)
|
||||||
value_test(false, is_pointer<int&>::value)
|
value_test(false, is_pointer<int&>::value)
|
||||||
value_test(true, is_pointer<int*>::value)
|
value_test(true, is_pointer<int*>::value)
|
||||||
|
value_test(true, is_pointer<const int*>::value)
|
||||||
|
value_test(true, is_pointer<volatile int*>::value)
|
||||||
|
value_test(true, is_pointer<non_pointer*>::value)
|
||||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||||
value_test(false, is_pointer<int*const>::value)
|
value_test(false, is_pointer<int*const>::value)
|
||||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||||
value_test(false, is_pointer<int*volatile>::value)
|
value_test(false, is_pointer<int*volatile>::value)
|
||||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||||
value_test(false, is_pointer<int*const volatile>::value)
|
value_test(false, is_pointer<int*const volatile>::value)
|
||||||
|
// JM 02 Oct 2000:
|
||||||
|
value_test(false, is_pointer<non_pointer>::value)
|
||||||
|
value_test(false, is_pointer<int*&>::value)
|
||||||
|
value_test(false, is_pointer<int(&)[2]>::value)
|
||||||
|
value_test(false, is_pointer<int[2]>::value)
|
||||||
|
value_test(false, is_pointer<char[sizeof(void*)]>::value)
|
||||||
|
|
||||||
value_test(true, is_pointer<f1>::value)
|
value_test(true, is_pointer<f1>::value)
|
||||||
value_test(true, is_pointer<f2>::value)
|
value_test(true, is_pointer<f2>::value)
|
||||||
value_test(true, is_pointer<f3>::value)
|
value_test(true, is_pointer<f3>::value)
|
||||||
@@ -398,6 +440,7 @@ int main()
|
|||||||
value_test(true, is_reference<volatile int &>::value)
|
value_test(true, is_reference<volatile int &>::value)
|
||||||
value_test(true, is_reference<r_type>::value)
|
value_test(true, is_reference<r_type>::value)
|
||||||
value_test(true, is_reference<cr_type>::value)
|
value_test(true, is_reference<cr_type>::value)
|
||||||
|
value_test(true, is_reference<const UDT&>::value)
|
||||||
|
|
||||||
value_test(false, is_class<int>::value)
|
value_test(false, is_class<int>::value)
|
||||||
value_test(false, is_class<const int>::value)
|
value_test(false, is_class<const int>::value)
|
||||||
@@ -439,19 +482,29 @@ int main()
|
|||||||
value_test(false, is_empty<int>::value)
|
value_test(false, is_empty<int>::value)
|
||||||
value_test(false, is_empty<int*>::value)
|
value_test(false, is_empty<int*>::value)
|
||||||
value_test(false, is_empty<int&>::value)
|
value_test(false, is_empty<int&>::value)
|
||||||
#ifdef __MWERKS__
|
#if defined(__MWERKS__) || defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
// apparent compiler bug causes this to fail to compile:
|
// apparent compiler bug causes this to fail to compile:
|
||||||
value_fail(false, is_empty<int[2]>::value)
|
value_fail(false, is_empty<int[2]>::value)
|
||||||
#else
|
#else
|
||||||
value_test(false, is_empty<int[2]>::value)
|
value_test(false, is_empty<int[2]>::value)
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
|
value_fail(false, is_empty<f1>::value)
|
||||||
|
#else
|
||||||
value_test(false, is_empty<f1>::value)
|
value_test(false, is_empty<f1>::value)
|
||||||
|
#endif
|
||||||
value_test(false, is_empty<mf1>::value)
|
value_test(false, is_empty<mf1>::value)
|
||||||
value_test(false, is_empty<UDT>::value)
|
value_test(false, is_empty<UDT>::value)
|
||||||
value_test(true, is_empty<empty_UDT>::value)
|
value_test(true, is_empty<empty_UDT>::value)
|
||||||
value_test(true, is_empty<empty_POD_UDT>::value)
|
value_test(true, is_empty<empty_POD_UDT>::value)
|
||||||
|
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
|
value_fail(true, is_empty<empty_union_UDT>::value)
|
||||||
|
#else
|
||||||
value_test(true, is_empty<empty_union_UDT>::value)
|
value_test(true, is_empty<empty_union_UDT>::value)
|
||||||
|
#endif
|
||||||
value_test(false, is_empty<enum_UDT>::value)
|
value_test(false, is_empty<enum_UDT>::value)
|
||||||
|
value_test(true, is_empty<boost::noncopyable>::value)
|
||||||
|
value_test(false, is_empty<non_empty>::value)
|
||||||
|
|
||||||
value_test(true, has_trivial_constructor<int>::value)
|
value_test(true, has_trivial_constructor<int>::value)
|
||||||
value_test(true, has_trivial_constructor<int*>::value)
|
value_test(true, has_trivial_constructor<int*>::value)
|
||||||
@@ -530,6 +583,57 @@ int main()
|
|||||||
value_test(false, is_POD<empty_UDT>::value)
|
value_test(false, is_POD<empty_UDT>::value)
|
||||||
value_test(true, is_POD<enum_UDT>::value)
|
value_test(true, is_POD<enum_UDT>::value)
|
||||||
|
|
||||||
|
value_test(true, (boost::is_convertible<Deriverd,Base>::value));
|
||||||
|
value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value));
|
||||||
|
value_test(true, (boost::is_convertible<Base,Base>::value));
|
||||||
|
value_test(false, (boost::is_convertible<Base,Deriverd>::value));
|
||||||
|
value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value));
|
||||||
|
value_test(false, (boost::is_convertible<NonDerived,Base>::value));
|
||||||
|
value_test(false, (boost::is_convertible<boost::noncopyable, int>::value));
|
||||||
|
value_test(true, (boost::is_convertible<float,int>::value));
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
|
value_test(false, (boost::is_convertible<float,void>::value));
|
||||||
|
value_test(false, (boost::is_convertible<void,float>::value));
|
||||||
|
value_test(true, (boost::is_convertible<void,void>::value));
|
||||||
|
#endif
|
||||||
|
value_test(true, (boost::is_convertible<enum1, int>::value));
|
||||||
|
value_test(true, (boost::is_convertible<Deriverd*, Base*>::value));
|
||||||
|
value_test(false, (boost::is_convertible<Base*, Deriverd*>::value));
|
||||||
|
value_test(true, (boost::is_convertible<Deriverd&, Base&>::value));
|
||||||
|
value_test(false, (boost::is_convertible<Base&, Deriverd&>::value));
|
||||||
|
value_test(true, (boost::is_convertible<const Deriverd*, const Base*>::value));
|
||||||
|
value_test(false, (boost::is_convertible<const Base*, const Deriverd*>::value));
|
||||||
|
value_test(true, (boost::is_convertible<const Deriverd&, const Base&>::value));
|
||||||
|
value_test(false, (boost::is_convertible<const Base&, const Deriverd&>::value));
|
||||||
|
|
||||||
|
value_test(false, (boost::is_convertible<const int *, int*>::value));
|
||||||
|
value_test(false, (boost::is_convertible<const int&, int&>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int*, int[2]>::value));
|
||||||
|
value_test(false, (boost::is_convertible<const int*, int[3]>::value));
|
||||||
|
value_test(true, (boost::is_convertible<const int&, int>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int(&)[4], const int*>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int(&)(int), int(*)(int)>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int *, const int*>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int&, const int&>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int[2], int*>::value));
|
||||||
|
value_test(true, (boost::is_convertible<int[2], const int*>::value));
|
||||||
|
value_test(false, (boost::is_convertible<const int[2], int*>::value));
|
||||||
|
|
||||||
|
align_test(int);
|
||||||
|
align_test(char);
|
||||||
|
align_test(double);
|
||||||
|
align_test(int[4]);
|
||||||
|
align_test(int(*)(int));
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
align_test(char&);
|
||||||
|
align_test(char (&)(int));
|
||||||
|
align_test(char(&)[4]);
|
||||||
|
#endif
|
||||||
|
align_test(int*);
|
||||||
|
//align_test(const int);
|
||||||
|
align_test(VB);
|
||||||
|
align_test(VD);
|
||||||
|
|
||||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||||
std::cin.get();
|
std::cin.get();
|
||||||
return failures;
|
return failures;
|
||||||
|
112
type_traits_test.hpp
Normal file
112
type_traits_test.hpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// boost::compressed_pair test program
|
||||||
|
|
||||||
|
// (C) Copyright John Maddock 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.
|
||||||
|
|
||||||
|
// common test code for type_traits_test.cpp/call_traits_test.cpp/compressed_pair_test.cpp
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BOOST_TYPE_TRAITS_TEST_HPP
|
||||||
|
#define BOOST_TYPE_TRAITS_TEST_HPP
|
||||||
|
|
||||||
|
//
|
||||||
|
// this one is here just to suppress warnings:
|
||||||
|
//
|
||||||
|
template <class T>
|
||||||
|
bool do_compare(T i, T j)
|
||||||
|
{
|
||||||
|
return i == j;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// this one is to verify that a constant is indeed a
|
||||||
|
// constant-integral-expression:
|
||||||
|
//
|
||||||
|
template <int>
|
||||||
|
struct ct_checker
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
|
||||||
|
#define BOOST_DO_JOIN2(X, Y) X##Y
|
||||||
|
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
|
||||||
|
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#define value_test(v, x) ++test_count;\
|
||||||
|
{typedef ct_checker<(x)> this_is_a_compile_time_check_;}\
|
||||||
|
if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
||||||
|
#else
|
||||||
|
#define value_test(v, x) ++test_count;\
|
||||||
|
typedef ct_checker<(x)> BOOST_JOIN(this_is_a_compile_time_check_, __LINE__);\
|
||||||
|
if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
||||||
|
#endif
|
||||||
|
#define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
#define type_test(v, x) ++test_count;\
|
||||||
|
if(do_compare(boost::is_same<v, x>::value, false)){\
|
||||||
|
++failures; \
|
||||||
|
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
||||||
|
std::cout << " expected type was " << #v << std::endl; \
|
||||||
|
std::cout << " " << typeid(boost::is_same<v, x>).name() << "::value is false" << std::endl; }
|
||||||
|
#else
|
||||||
|
#define type_test(v, x) ++test_count;\
|
||||||
|
if(typeid(v) != typeid(x)){\
|
||||||
|
++failures; \
|
||||||
|
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
||||||
|
std::cout << " expected type was " << #v << std::endl; \
|
||||||
|
std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct test_align
|
||||||
|
{
|
||||||
|
struct padded
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
T t;
|
||||||
|
};
|
||||||
|
static void do_it()
|
||||||
|
{
|
||||||
|
padded p;
|
||||||
|
unsigned a = reinterpret_cast<char*>(&(p.t)) - reinterpret_cast<char*>(&p);
|
||||||
|
value_test(a, boost::alignment_of<T>::value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
template <class T>
|
||||||
|
struct test_align<T&>
|
||||||
|
{
|
||||||
|
static void do_it()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// we can't do the usual test because we can't take the address
|
||||||
|
// of a reference, so check that the result is the same as for a
|
||||||
|
// pointer type instead:
|
||||||
|
value_test(boost::alignment_of<T*>::value, boost::alignment_of<T&>::value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define align_test(T) test_align<T>::do_it()
|
||||||
|
|
||||||
|
//
|
||||||
|
// define tests here
|
||||||
|
unsigned failures = 0;
|
||||||
|
unsigned test_count = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// turn off some warnings:
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma option -w-8004
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOST_MSVC
|
||||||
|
#pragma warning (disable: 4018)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_TYPE_TRAITS_TEST_HPP
|
||||||
|
|
@@ -16,10 +16,11 @@
|
|||||||
<h2>Contents</h2>
|
<h2>Contents</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Template functions <a href="#functions next">next() and prior()</a></li>
|
<li>Function templates <a href="#functions next">next() and prior()</a></li>
|
||||||
<li>Class <a href="#Class noncopyable">noncopyable</a></li>
|
<li>Class <a href="#Class noncopyable">noncopyable</a></li>
|
||||||
|
<li>Function template <a href="tie.html">tie()</a> and supporting class tied.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Template <a name="functions next">functions next</a>() and prior()</h2>
|
<h2> <a name="functions next">Function</a> templates next() and prior()</h2>
|
||||||
|
|
||||||
<p>Certain data types, such as the C++ Standard Library's forward and
|
<p>Certain data types, such as the C++ Standard Library's forward and
|
||||||
bidirectional iterators, do not provide addition and subtraction via operator+()
|
bidirectional iterators, do not provide addition and subtraction via operator+()
|
||||||
@@ -92,7 +93,7 @@ destructor declarations. He says "Probably this concern is misplaced, becau
|
|||||||
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p>
|
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
|
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
|
||||||
-->26 January, 2000<!--webbot bot="Timestamp" endspan i-checksum="38194"
|
-->28 September, 2000<!--webbot bot="Timestamp" endspan i-checksum="39343"
|
||||||
-->
|
-->
|
||||||
</p>
|
</p>
|
||||||
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
|
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
|
||||||
|
Reference in New Issue
Block a user