forked from boostorg/utility
Compare commits
256 Commits
svn-branch
...
svn-branch
Author | SHA1 | Date | |
---|---|---|---|
|
7cfd6f756d | ||
|
4e1b693ee2 | ||
|
e7592e5f83 | ||
|
d41013d9dc | ||
|
c3c8871f87 | ||
|
7b2f7a5ab4 | ||
|
bef6ec31f0 | ||
|
7657f5f343 | ||
|
1a31e19cfe | ||
|
82377d5130 | ||
|
4fe8f1505f | ||
|
c11ba92add | ||
|
c3cb4753f5 | ||
|
80eb3699d7 | ||
|
0e40c56a87 | ||
|
4a79874032 | ||
|
4e07a06b94 | ||
|
884c36772a | ||
|
506334c120 | ||
|
89107738b3 | ||
|
397946a114 | ||
|
ddbc514208 | ||
|
2cef48d02a | ||
|
96a079e30a | ||
|
4a3f6877e2 | ||
|
c593a27a51 | ||
|
f94db51996 | ||
|
3e5b447aa3 | ||
|
2f9bd13902 | ||
|
c59a5e8783 | ||
|
5b716a8b19 | ||
|
c243d693e2 | ||
|
b950b3afed | ||
|
1c555eae91 | ||
|
f04178d055 | ||
|
b38bc8d848 | ||
|
9c2549bd00 | ||
|
b7c8e0c17f | ||
|
dd3cfe1837 | ||
|
43f525298e | ||
|
1bb1898ab9 | ||
|
9578f24be9 | ||
|
46fae3aed2 | ||
|
e35f91a70a | ||
|
851052fcca | ||
|
5ef81b2952 | ||
|
ef2851c053 | ||
|
0b4387cff5 | ||
|
a40cf11fbf | ||
|
5c495cd223 | ||
|
cf1296dff8 | ||
|
d6d88db6e8 | ||
|
85c2a35257 | ||
|
836d8b1c64 | ||
|
98d8c8ab71 | ||
|
db45013339 | ||
|
a55c37e7f6 | ||
|
46a270fcca | ||
|
967856518e | ||
|
7f93e739fe | ||
|
2cd1422514 | ||
|
feb370b201 | ||
|
d1b34e64d8 | ||
|
b9a1eead40 | ||
|
1e4bfac98c | ||
|
3bb504fbf3 | ||
|
5029791c90 | ||
|
a1a68f0970 | ||
|
f8543d79eb | ||
|
f353415136 | ||
|
26240403b0 | ||
|
3a39729b58 | ||
|
096c961d9a | ||
|
01fe04a6a2 | ||
|
7ea4014993 | ||
|
d50b374f88 | ||
|
27dfb25570 | ||
|
b5ed77985e | ||
|
61243bd15f | ||
|
368b94d804 | ||
|
a5adbbfd5f | ||
|
a19d13f123 | ||
|
78886ab383 | ||
|
168012b465 | ||
|
d9d58ea66e | ||
|
56f5f6e8d5 | ||
|
3cb6420eda | ||
|
60be2c1186 | ||
|
ed210f6b2c | ||
|
029bc59d74 | ||
|
961c08a82f | ||
|
7ee484c614 | ||
|
05c6fbbf99 | ||
|
91078b7f7a | ||
|
20d804afc4 | ||
|
c21f6d1cbf | ||
|
393e79c1fd | ||
|
8b92c8a085 | ||
|
ff73dd94c9 | ||
|
af43904f38 | ||
|
485074f265 | ||
|
2e0ee55b5e | ||
|
e9105d32cb | ||
|
964d23f68c | ||
|
be5aaaae7b | ||
|
bf13bd7b3f | ||
|
352e392fcb | ||
|
083b1b02df | ||
|
648c6240a2 | ||
|
60cab840cb | ||
|
83a4380dab | ||
|
de84fe8d98 | ||
|
ed3cbfdb8e | ||
|
fda44ca17d | ||
|
272025bb07 | ||
|
8e92bcf1b2 | ||
|
84f1ffdefe | ||
|
7e25450054 | ||
|
4a563fa266 | ||
|
aa4c0ec000 | ||
|
e1ecfbdc43 | ||
|
a4e122a82e | ||
|
93216e8fb7 | ||
|
16272c210d | ||
|
e104b00da1 | ||
|
ce5c6bcc08 | ||
|
8694ce31fe | ||
|
d960e5eadd | ||
|
2dc71e87a3 | ||
|
6bf17edde2 | ||
|
88573d515d | ||
|
89b9f77823 | ||
|
765d9be17d | ||
|
7135373008 | ||
|
ee269884fc | ||
|
387540d5f1 | ||
|
2eba7b42a8 | ||
|
07115d26c7 | ||
|
c43ed815a0 | ||
|
ff01e36d12 | ||
|
ac4798b16c | ||
|
d4e14fed0e | ||
|
5f91259344 | ||
|
20a9d9645d | ||
|
c86f6b4abd | ||
|
d66489b5b2 | ||
|
b743ee9f0c | ||
|
95ba69c00a | ||
|
2ac273739c | ||
|
5b4d28708c | ||
|
4cc4383488 | ||
|
8935232248 | ||
|
5c6dd2f172 | ||
|
eeeb7ef5b9 | ||
|
2efc9c1178 | ||
|
a84c46f6e3 | ||
|
a5c3dcdd02 | ||
|
46f7a75eb7 | ||
|
94b6710c5b | ||
|
d8dd3da9ab | ||
|
803ced004a | ||
|
0ea7d36ad0 | ||
|
87aafab759 | ||
|
994d310abd | ||
|
228cdcf05e | ||
|
42598e352c | ||
|
36a9e4d1da | ||
|
456dfd0dea | ||
|
155457e2b5 | ||
|
b5c91485bf | ||
|
c959cf7870 | ||
|
5878c88636 | ||
|
ddcef2fb19 | ||
|
493d124c07 | ||
|
f42060c616 | ||
|
834facc932 | ||
|
f82d0b76ee | ||
|
c25d225275 | ||
|
c503a274b5 | ||
|
087069d215 | ||
|
826a6dd114 | ||
|
f31483838d | ||
|
d8a9b633d9 | ||
|
c060e4466a | ||
|
a9951376f4 | ||
|
bda0c8f5e3 | ||
|
71902f23a2 | ||
|
dfd6c85569 | ||
|
0e41b2cc1a | ||
|
e5c81d0702 | ||
|
6caf7d4d5a | ||
|
98e87c8afb | ||
|
d9e0f80d50 | ||
|
6396fdb5ff | ||
|
2470b53373 | ||
|
16334e92ca | ||
|
c22d98a8ec | ||
|
28617afbb9 | ||
|
0c3bc42bec | ||
|
e3d9745df1 | ||
|
b8471c1015 | ||
|
045b09c9ef | ||
|
4ac07b97d3 | ||
|
34c847c17f | ||
|
f694e557e1 | ||
|
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 | ||
|
2086542bfb | ||
|
e52916acf2 | ||
|
767b61a254 | ||
|
ba62287576 | ||
|
b231894f1b | ||
|
d83ea9e52e | ||
|
777c931b5d |
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/tech/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>Copy Constructible</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>Copy Constructible</H1>
|
||||
|
||||
<h3>Description</h3>
|
||||
A type is Copy Constructible 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 Copy Constructible
|
||||
</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/tech/stl/DefaultConstructible.html">Default Constructible</A>
|
||||
and
|
||||
<A hrefa="./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/tech/stl/EqualityComparable.html">EqualityComparable</A>, <A href="http://www.sgi.com/tech/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>
|
||||
Multi-Pass Input Iterator
|
||||
</H2>
|
||||
|
||||
This concept is a refinement of <a
|
||||
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</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
|
||||
Multi-Pass Input Iterator is very similar to the <a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.hmtl">Forward Iterator</a>. The
|
||||
only difference is that a <a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.hmtl">Forward Iterator</a>
|
||||
requires the <TT>reference</TT> type to be <TT>value_type&</TT>, whereas
|
||||
MultiPassInputIterator is like <a
|
||||
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</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 Multi-Pass Input Iterator isn't the right
|
||||
solution. Do you also want to define Multi-Pass Bidirectionnal Iterator
|
||||
and Multi-Pass Random Access Iterator ? 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 Random Access 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 Multi-Pass Input Iterator
|
||||
is just called a Forward Iterator.
|
||||
|
||||
<p>
|
||||
Other translations are:<br>
|
||||
std::Forward Iterator -> ForwardIterator & Lvalue Iterator<br>
|
||||
std::Bidirectionnal Iterator -> Bidirectionnal Iterator & Lvalue Iterator<br>
|
||||
std::Random Access Iterator -> Random Access Iterator & Lvalue Iterator<br>
|
||||
|
||||
<p>
|
||||
Note that in practice the only operation not allowed on my
|
||||
Forward Iterator which is allowed on std::Forward Iterator 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 Forward Iterator. The right course
|
||||
of action is to get Forward Iterator, etc. changed in the C++ standard.
|
||||
Once that is done we can drop Multi-Pass Input Iterator.
|
||||
|
||||
|
||||
<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>
|
@@ -1,423 +0,0 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1999
|
||||
* Dr John Maddock
|
||||
*
|
||||
* 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 appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Dr John Maddock makes no representations
|
||||
* about the suitability of this software for any purpose.
|
||||
* It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* This file provides some example of type_traits usage -
|
||||
* by "optimising" various algorithms:
|
||||
*
|
||||
* opt::copy - optimised for trivial copy (cf std::copy)
|
||||
* opt::fill - optimised for trivial copy/small types (cf std::fill)
|
||||
* opt::destroy_array - an example of optimisation based upon omitted destructor calls
|
||||
* opt::iter_swap - uses type_traits to determine whether the iterator is a proxy
|
||||
* in which case it uses a "safe" approach, otherwise calls swap
|
||||
* on the assumption that swap may be specialised for the pointed-to type.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Release notes:
|
||||
23rd July 2000:
|
||||
Added explicit failure for broken compilers that don't support these examples.
|
||||
Fixed broken gcc support (broken using directive).
|
||||
Reordered tests slightly.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/timer.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::cin;
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
#error "Sorry, without template partial specialisation support there isn't anything to test here..."
|
||||
#endif
|
||||
|
||||
namespace opt{
|
||||
|
||||
//
|
||||
// algorithm destroy_arry:
|
||||
// The reverse of std::unitialized_copy, takes a block of
|
||||
// unitialized memory and calls destructors on all objects therein.
|
||||
//
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <bool>
|
||||
struct array_destroyer
|
||||
{
|
||||
template <class T>
|
||||
static void destroy_array(T* i, T* j){ do_destroy_array(i, j); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct array_destroyer<true>
|
||||
{
|
||||
template <class T>
|
||||
static void destroy_array(T*, T*){}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void do_destroy_array(T* first, T* last)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
first->~T();
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline void destroy_array(T* p1, T* p2)
|
||||
{
|
||||
detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2);
|
||||
}
|
||||
|
||||
//
|
||||
// unoptimised versions of destroy_array:
|
||||
//
|
||||
template <class T>
|
||||
void destroy_array1(T* first, T* last)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
first->~T();
|
||||
++first;
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
void destroy_array2(T* first, T* last)
|
||||
{
|
||||
for(; first != last; ++first) first->~T();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// opt::copy
|
||||
// same semantics as std::copy
|
||||
// calls memcpy where appropiate.
|
||||
//
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <bool b>
|
||||
struct copier
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2 do_copy(I1 first, I1 last, I2 out);
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
template<typename I1, typename I2>
|
||||
I2 copier<b>::do_copy(I1 first, I1 last, I2 out)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*out = *first;
|
||||
++out;
|
||||
++first;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct copier<true>
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2* do_copy(I1* first, I1* last, I2* out)
|
||||
{
|
||||
memcpy(out, first, (last-first)*sizeof(I2));
|
||||
return out+(last-first);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename I1, typename I2>
|
||||
inline I2 copy(I1 first, I1 last, I2 out)
|
||||
{
|
||||
typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t;
|
||||
typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t;
|
||||
enum{ can_opt = boost::is_same<v1_t, v2_t>::value
|
||||
&& boost::is_pointer<I1>::value
|
||||
&& boost::is_pointer<I2>::value
|
||||
&& boost::has_trivial_assign<v1_t>::value };
|
||||
return detail::copier<can_opt>::do_copy(first, last, out);
|
||||
}
|
||||
|
||||
//
|
||||
// fill
|
||||
// same as std::fill, uses memset where appropriate, along with call_traits
|
||||
// to "optimise" parameter passing.
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <bool opt>
|
||||
struct filler
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val);
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
template <typename I, typename T>
|
||||
void filler<b>::do_fill(I first, I last, typename boost::call_traits<T>::param_type val)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*first = val;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct filler<true>
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, T val)
|
||||
{
|
||||
memset(first, val, last-first);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class I, class T>
|
||||
inline void fill(I first, I last, const T& val)
|
||||
{
|
||||
enum{ can_opt = boost::is_pointer<I>::value
|
||||
&& boost::is_arithmetic<T>::value
|
||||
&& (sizeof(T) == 1) };
|
||||
typedef detail::filler<can_opt> filler_t;
|
||||
filler_t::template do_fill<I,T>(first, last, val);
|
||||
}
|
||||
|
||||
//
|
||||
// iter_swap:
|
||||
// tests whether iterator is a proxying iterator or not, and
|
||||
// uses optimal form accordingly:
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <bool b>
|
||||
struct swapper
|
||||
{
|
||||
template <typename I>
|
||||
static void do_swap(I one, I two)
|
||||
{
|
||||
typedef typename std::iterator_traits<I>::value_type v_t;
|
||||
v_t v = *one;
|
||||
*one = *two;
|
||||
*two = v;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
using std::swap;
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct swapper<true>
|
||||
{
|
||||
template <typename I>
|
||||
static void do_swap(I one, I two)
|
||||
{
|
||||
using std::swap;
|
||||
swap(*one, *two);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename I1, typename I2>
|
||||
inline void iter_swap(I1 one, I2 two)
|
||||
{
|
||||
typedef typename std::iterator_traits<I1>::reference r1_t;
|
||||
typedef typename std::iterator_traits<I2>::reference r2_t;
|
||||
enum{ can_opt = boost::is_reference<r1_t>::value && boost::is_reference<r2_t>::value && boost::is_same<r1_t, r2_t>::value };
|
||||
detail::swapper<can_opt>::do_swap(one, two);
|
||||
}
|
||||
|
||||
|
||||
}; // namespace opt
|
||||
|
||||
//
|
||||
// define some global data:
|
||||
//
|
||||
const int array_size = 1000;
|
||||
int i_array[array_size] = {0,};
|
||||
const int ci_array[array_size] = {0,};
|
||||
char c_array[array_size] = {0,};
|
||||
const char cc_array[array_size] = { 0,};
|
||||
|
||||
const int iter_count = 1000000;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
//
|
||||
// test destroy_array,
|
||||
// compare destruction time of an array of ints
|
||||
// with unoptimised form.
|
||||
//
|
||||
cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
|
||||
cout << "testing destroy_array...\n"
|
||||
"[Some compilers may be able to optimise the \"unoptimised\"\n versions as well as type_traits does.]" << endl;
|
||||
/*cache load*/ opt::destroy_array(i_array, i_array + array_size);
|
||||
boost::timer t;
|
||||
double result;
|
||||
int i;
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>: " << result << endl;
|
||||
/*cache load*/ opt::destroy_array1(i_array, i_array + array_size);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array1(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>(unoptimised#1): " << result << endl;
|
||||
/*cache load*/ opt::destroy_array2(i_array, i_array + array_size);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array2(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>(unoptimised#2): " << result << endl << endl;
|
||||
|
||||
cout << "testing fill(char)...\n"
|
||||
"[Some standard library versions may already perform this optimisation.]" << endl;
|
||||
/*cache load*/ opt::fill<char*, char>(c_array, c_array + array_size, (char)3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::fill<char*, char>(c_array, c_array + array_size, (char)3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::fill<char*, char>: " << result << endl;
|
||||
/*cache load*/ std::fill(c_array, c_array + array_size, (char)3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::fill(c_array, c_array + array_size, (char)3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::fill<char*, char>: " << result << endl << endl;
|
||||
|
||||
cout << "testing fill(int)...\n"
|
||||
"[Tests the effect of call_traits pass-by-value optimisation -\nthe value of this optimisation may depend upon hardware characteristics.]" << endl;
|
||||
/*cache load*/ opt::fill<int*, int>(i_array, i_array + array_size, 3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::fill<int*, int>(i_array, i_array + array_size, 3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::fill<int*, int>: " << result << endl;
|
||||
/*cache load*/ std::fill(i_array, i_array + array_size, 3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::fill(i_array, i_array + array_size, 3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::fill<int*, int>: " << result << endl << endl;
|
||||
|
||||
cout << "testing copy...\n"
|
||||
"[Some standard library versions may already perform this optimisation.]" << endl;
|
||||
/*cache load*/ opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::copy<const int*, int*>: " << result << endl;
|
||||
/*cache load*/ std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::copy<const int*, int*>: " << result << endl;
|
||||
/*cache load*/ opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "standard \"unoptimised\" copy: " << result << endl << endl;
|
||||
|
||||
/*cache load*/ opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::copy<const char*, char*>: " << result << endl;
|
||||
/*cache load*/ std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::copy<const char*, char*>: " << result << endl;
|
||||
/*cache load*/ opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "standard \"unoptimised\" copy: " << result << endl << endl;
|
||||
|
||||
|
||||
//
|
||||
// testing iter_swap
|
||||
// really just a check that it does in fact compile...
|
||||
std::vector<int> v1;
|
||||
v1.push_back(0);
|
||||
v1.push_back(1);
|
||||
std::vector<bool> v2;
|
||||
v2.push_back(0);
|
||||
v2.push_back(1);
|
||||
opt::iter_swap(v1.begin(), v1.begin()+1);
|
||||
opt::iter_swap(v2.begin(), v2.begin()+1);
|
||||
|
||||
cout << "Press any key to exit...";
|
||||
cin.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
762
call_traits.htm
Normal file
762
call_traits.htm
Normal file
@@ -0,0 +1,762 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type"
|
||||
content="text/html; charset=iso-8859-1">
|
||||
<meta name="Template"
|
||||
content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<title>Call Traits</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
|
||||
vlink="#800080">
|
||||
|
||||
<h1><img src="../../c++boost.gif" width="276" height="86">Header
|
||||
<<a href="../../boost/detail/call_traits.hpp">boost/call_traits.hpp</a>></h1>
|
||||
|
||||
<p>All of the contents of <boost/call_traits.hpp> are
|
||||
defined inside namespace boost.</p>
|
||||
|
||||
<p>The template class call_traits<T> encapsulates the
|
||||
"best" method to pass a parameter of some type T to or
|
||||
from a function, and consists of a collection of typedefs defined
|
||||
as in the table below. The purpose of call_traits is to ensure
|
||||
that problems like "<a href="#refs">references to references</a>"
|
||||
never occur, and that parameters are passed in the most efficient
|
||||
manner possible (see <a href="#examples">examples</a>). In each
|
||||
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
|
||||
right. </p>
|
||||
|
||||
<p>Note that for compilers that do not support either partial
|
||||
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">
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#008080"><p
|
||||
align="center">Existing practice</p>
|
||||
</td>
|
||||
<td valign="top" width="35%" bgcolor="#008080"><p
|
||||
align="center">call_traits equivalent</p>
|
||||
</td>
|
||||
<td valign="top" width="32%" bgcolor="#008080"><p
|
||||
align="center">Description</p>
|
||||
</td>
|
||||
<td valign="top" width="16%" bgcolor="#008080"><p
|
||||
align="center">Notes</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%"><p align="center">T<br>
|
||||
(return by value)</p>
|
||||
</td>
|
||||
<td valign="top" width="35%"><p align="center"><code>call_traits<T>::value_type</code></p>
|
||||
</td>
|
||||
<td valign="top" width="32%">Defines a type that
|
||||
represents the "value" of type T. Use this for
|
||||
functions that return by value, or possibly for stored
|
||||
values of type T.</td>
|
||||
<td valign="top" width="16%"><p align="center">2</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%"><p align="center">T&<br>
|
||||
(return value)</p>
|
||||
</td>
|
||||
<td valign="top" width="35%"><p align="center"><code>call_traits<T>::reference</code></p>
|
||||
</td>
|
||||
<td valign="top" width="32%">Defines a type that
|
||||
represents a reference to type T. Use for functions that
|
||||
would normally return a T&.</td>
|
||||
<td valign="top" width="16%"><p align="center">1</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
T&<br>
|
||||
(return value)</p>
|
||||
</td>
|
||||
<td valign="top" width="35%"><p align="center"><code>call_traits<T>::const_reference</code></p>
|
||||
</td>
|
||||
<td valign="top" width="32%">Defines a type that
|
||||
represents a constant reference to type T. Use for
|
||||
functions that would normally return a const T&.</td>
|
||||
<td valign="top" width="16%"><p align="center">1</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
T&<br>
|
||||
(function parameter)</p>
|
||||
</td>
|
||||
<td valign="top" width="35%"><p align="center"><code>call_traits<T>::param_type</code></p>
|
||||
</td>
|
||||
<td valign="top" width="32%">Defines a type that
|
||||
represents the "best" way to pass a parameter
|
||||
of type T to a function.</td>
|
||||
<td valign="top" width="16%"><p align="center">1,3</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Notes:</p>
|
||||
|
||||
<ol>
|
||||
<li>If T is already reference type, then call_traits is
|
||||
defined such that <a href="#refs">references to
|
||||
references</a> do not occur (requires partial
|
||||
specialization).</li>
|
||||
<li>If T is an array type, then call_traits defines <code>value_type</code>
|
||||
as a "constant pointer to type" rather than an
|
||||
"array of type" (requires partial
|
||||
specialization). Note that if you are using value_type as
|
||||
a stored value then this will result in storing a "constant
|
||||
pointer to an array" rather than the array itself.
|
||||
This may or may not be a good thing depending upon what
|
||||
you actually need (in other words take care!).</li>
|
||||
<li>If T is a small built in type or a pointer, then <code>param_type</code>
|
||||
is defined as <code>T const</code>, instead of <code>T
|
||||
const&</code>. This can improve the ability of the
|
||||
compiler to optimize loops in the body of the function if
|
||||
they depend upon the passed parameter, the semantics of
|
||||
the passed parameter is otherwise unchanged (requires
|
||||
partial specialization).</li>
|
||||
</ol>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3>Copy constructibility</h3>
|
||||
|
||||
<p>The following table defines which call_traits types can always
|
||||
be copy-constructed from which other types, those entries marked
|
||||
with a '?' are true only if and only if T is copy constructible:</p>
|
||||
|
||||
<table border="0" cellpadding="7" cellspacing="1" width="766">
|
||||
<tr>
|
||||
<td valign="top" width="17%"> </td>
|
||||
<td valign="top" colspan="5" width="85%"
|
||||
bgcolor="#008080"><p align="center">To:</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#008080">From:</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">T</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">value_type</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">const_reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">param_type</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">T</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">value_type</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">reference</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">const_reference</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">param_type</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">?</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">N</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p>If T is an assignable type the following assignments are
|
||||
possible:</p>
|
||||
|
||||
<table border="0" cellpadding="7" cellspacing="1" width="766">
|
||||
<tr>
|
||||
<td valign="top" width="17%"> </td>
|
||||
<td valign="top" colspan="5" width="85%"
|
||||
bgcolor="#008080"><p align="center">To:</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#008080">From:</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">T</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">value_type</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">const_reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">param_type</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">T</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">value_type</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">reference</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">const_reference</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0">param_type</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">Y</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">-</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3><a name="examples"></a>Examples</h3>
|
||||
|
||||
<p>The following table shows the effect that call_traits has on
|
||||
various types, the table assumes that the compiler supports
|
||||
partial specialization: if it doesn't then all types behave in
|
||||
the same way as the entry for "myclass", and
|
||||
call_traits can not be used with reference or array types.</p>
|
||||
|
||||
<table border="0" cellpadding="7" cellspacing="1" width="766">
|
||||
<tr>
|
||||
<td valign="top" width="17%"> </td>
|
||||
<td valign="top" colspan="5" width="85%"
|
||||
bgcolor="#008080"><p align="center">Call_traits type:</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#008080"><p
|
||||
align="center">Original type T</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">value_type</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">const_reference</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">param_type</p>
|
||||
</td>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">Applies to:</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">myclass</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">myclass</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">myclass&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
myclass&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">myclass
|
||||
const&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All user
|
||||
defined types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">int</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int const</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All small
|
||||
built-in types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">int*</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int*</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int*&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int*const&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int* const</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All
|
||||
pointer types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All
|
||||
reference types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">const int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const
|
||||
int&</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All
|
||||
constant-references.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">int[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int*</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">int(&)[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int(&)[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int*
|
||||
const</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All array
|
||||
types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="17%" bgcolor="#C0C0C0"><p
|
||||
align="center">const int[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int*</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int(&)[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int(&)[3]</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">const int*
|
||||
const</p>
|
||||
</td>
|
||||
<td valign="top" width="17%"><p align="center">All
|
||||
constant-array types.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h4>Example 1:</h4>
|
||||
|
||||
<p>The following class is a trivial class that stores some type T
|
||||
by value (see the <a href="call_traits_test.cpp">call_traits_test.cpp</a>
|
||||
file), the aim is to illustrate how each of the available
|
||||
call_traits typedefs may be used:</p>
|
||||
|
||||
<pre>template <class T>
|
||||
struct contained
|
||||
{
|
||||
// define our typedefs first, arrays are stored by value
|
||||
// so value_type is not the same as result_type:
|
||||
typedef typename boost::call_traits<T>::param_type param_type;
|
||||
typedef typename boost::call_traits<T>::reference reference;
|
||||
typedef typename boost::call_traits<T>::const_reference const_reference;
|
||||
typedef T value_type;
|
||||
typedef typename boost::call_traits<T>::value_type result_type;
|
||||
|
||||
// stored value:
|
||||
value_type v_;
|
||||
|
||||
// constructors:
|
||||
contained() {}
|
||||
contained(param_type p) : v_(p){}
|
||||
// return byval:
|
||||
result_type value() { return v_; }
|
||||
// return by_ref:
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
// pass value:
|
||||
void call(param_type p){}
|
||||
|
||||
};</pre>
|
||||
|
||||
<h4><a name="refs"></a>Example 2 (the reference to reference
|
||||
problem):</h4>
|
||||
|
||||
<p>Consider the definition of std::binder1st:</p>
|
||||
|
||||
<pre>template <class Operation>
|
||||
class binder1st :
|
||||
public unary_function<typename Operation::second_argument_type, typename Operation::result_type>
|
||||
{
|
||||
protected:
|
||||
Operation op;
|
||||
typename Operation::first_argument_type value;
|
||||
public:
|
||||
binder1st(const Operation& x, const typename Operation::first_argument_type& y);
|
||||
typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const;
|
||||
}; </pre>
|
||||
|
||||
<p>Now consider what happens in the relatively common case that
|
||||
the functor takes its second argument as a reference, that
|
||||
implies that <code>Operation::second_argument_type</code> is a
|
||||
reference type, <code>operator()</code> will now end up taking a
|
||||
reference to a reference as an argument, and that is not
|
||||
currently legal. The solution here is to modify <code>operator()</code>
|
||||
to use call_traits:</p>
|
||||
|
||||
<pre>typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;</pre>
|
||||
|
||||
<p>Now in the case that <code>Operation::second_argument_type</code>
|
||||
is a reference type, the argument is passed as a reference, and
|
||||
the no "reference to reference" occurs.</p>
|
||||
|
||||
<h4><a name="ex3"></a>Example 3 (the make_pair problem):</h4>
|
||||
|
||||
<p>If we pass the name of an array as one (or both) arguments to <code>std::make_pair</code>,
|
||||
then template argument deduction deduces the passed parameter as
|
||||
"const reference to array of T", this also applies to
|
||||
string literals (which are really array literals). Consequently
|
||||
instead of returning a pair of pointers, it tries to return a
|
||||
pair of arrays, and since an array type is not copy-constructible
|
||||
the code fails to compile. One solution is to explicitly cast the
|
||||
arguments to make_pair to pointers, but call_traits provides a
|
||||
better (i.e. automatic) solution (and one that works safely even
|
||||
in generic code where the cast might do the wrong thing):</p>
|
||||
|
||||
<pre>template <class T1, class T2>
|
||||
std::pair<
|
||||
typename boost::call_traits<T1>::value_type,
|
||||
typename boost::call_traits<T2>::value_type>
|
||||
make_pair(const T1& t1, const T2& t2)
|
||||
{
|
||||
return std::pair<
|
||||
typename boost::call_traits<T1>::value_type,
|
||||
typename boost::call_traits<T2>::value_type>(t1, t2);
|
||||
}</pre>
|
||||
|
||||
<p>Here, the deduced argument types will be automatically
|
||||
degraded to pointers if the deduced types are arrays, similar
|
||||
situations occur in the standard binders and adapters: in
|
||||
principle in any function that "wraps" a temporary
|
||||
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>
|
||||
|
||||
<p>The call_traits template will "optimize" the passing
|
||||
of a small built-in type as a function parameter, this mainly has
|
||||
an effect when the parameter is used within a loop body. In the
|
||||
following example (see <a href="algo_opt_examples.cpp">algo_opt_examples.cpp</a>),
|
||||
a version of std::fill is optimized in two ways: if the type
|
||||
passed is a single byte built-in type then std::memset is used to
|
||||
effect the fill, otherwise a conventional C++ implemention is
|
||||
used, but with the passed parameter "optimized" using
|
||||
call_traits:</p>
|
||||
|
||||
<pre>namespace detail{
|
||||
|
||||
template <bool opt>
|
||||
struct filler
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val);
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*first = val;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct filler<true>
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, T val)
|
||||
{
|
||||
memset(first, val, last-first);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class I, class T>
|
||||
inline void fill(I first, I last, const T& val)
|
||||
{
|
||||
enum{ can_opt = boost::is_pointer<I>::value
|
||||
&& boost::is_arithmetic<T>::value
|
||||
&& (sizeof(T) == 1) };
|
||||
typedef detail::filler<can_opt> filler_t;
|
||||
filler_t::template do_fill<I,T>(first, last, val);
|
||||
}</pre>
|
||||
|
||||
<p>Footnote: the reason that this is "optimal" for
|
||||
small built-in types is that with the value passed as "T
|
||||
const" instead of "const T&" the compiler is
|
||||
able to tell both that the value is constant and that it is free
|
||||
of aliases. With this information the compiler is able to cache
|
||||
the passed value in a register, unroll the loop, or use
|
||||
explicitly parallel instructions: if any of these are supported.
|
||||
Exactly how much mileage you will get from this depends upon your
|
||||
compiler - we could really use some accurate benchmarking
|
||||
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>
|
||||
|
||||
<p>The following notes are intended to briefly describe the
|
||||
rational behind choices made in call_traits.</p>
|
||||
|
||||
<p>All user-defined types follow "existing practice"
|
||||
and need no comment.</p>
|
||||
|
||||
<p>Small built-in types (what the standard calls fundamental
|
||||
types [3.9.1]) differ from existing practice only in the <i>param_type</i>
|
||||
typedef. In this case passing "T const" is compatible
|
||||
with existing practice, but may improve performance in some cases
|
||||
(see <a href="#ex4">Example 4</a>), in any case this should never
|
||||
be any worse than existing practice.</p>
|
||||
|
||||
<p>Pointers follow the same rational as small built-in types.</p>
|
||||
|
||||
<p>For reference types the rational follows <a href="#refs">Example
|
||||
2</a> - references to references are not allowed, so the
|
||||
call_traits members must be defined such that these problems do
|
||||
not occur. There is a proposal to modify the language such that
|
||||
"a reference to a reference is a reference" (issue #106,
|
||||
submitted by Bjarne Stroustrup), call_traits<T>::value_type
|
||||
and call_traits<T>::param_type both provide the same effect
|
||||
as that proposal, without the need for a language change (in
|
||||
other words it's a workaround).</p>
|
||||
|
||||
<p>For array types, a function that takes an array as an argument
|
||||
will degrade the array type to a pointer type: this means that
|
||||
the type of the actual parameter is different from its declared
|
||||
type, something that can cause endless problems in template code
|
||||
that relies on the declared type of a parameter. For example:</p>
|
||||
|
||||
<pre>template <class T>
|
||||
struct A
|
||||
{
|
||||
void foo(T t);
|
||||
};</pre>
|
||||
|
||||
<p><font face="Times New Roman">In this case if we instantiate
|
||||
A<int[2]> then the declared type of the parameter passed to
|
||||
member function foo is int[2], but it's actual type is const int*,
|
||||
if we try to use the type T within the function body, then there
|
||||
is a strong likelyhood that our code will not compile:</font></p>
|
||||
|
||||
<pre>template <class T>
|
||||
void A<T>::foo(T t)
|
||||
{
|
||||
T dup(t); // doesn't compile for case that T is an array.
|
||||
}</pre>
|
||||
|
||||
<p>By using call_traits the degradation from array to pointer is
|
||||
explicit, and the type of the parameter is the same as it's
|
||||
declared type:</p>
|
||||
|
||||
<pre>template <class T>
|
||||
struct A
|
||||
{
|
||||
void foo(typename call_traits<T>::value_type t);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void A<T>::foo(typename call_traits<T>::value_type t)
|
||||
{
|
||||
typename call_traits<T>::value_type dup(t); // OK even if T is an array type.
|
||||
}</pre>
|
||||
|
||||
<p>For value_type (return by value), again only a pointer may be
|
||||
returned, not a copy of the whole array, and again call_traits
|
||||
makes the degradation explicit. The value_type member is useful
|
||||
whenever an array must be explicitly degraded to a pointer - <a
|
||||
href="#ex3">Example 3</a> provides the test case (Footnote: the
|
||||
array specialisation for call_traits is the least well understood
|
||||
of all the call_traits specialisations, if the given semantics
|
||||
cause specific problems for you, or don't solve a particular
|
||||
array-related problem, then I would be interested to hear about
|
||||
it. Most people though will probably never need to use this
|
||||
specialisation).</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 01 September 2000</p>
|
||||
|
||||
<p><EFBFBD> Copyright boost.org 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>
|
||||
|
||||
<p>Based on contributions by Steve Cleary, Beman Dawes, Howard
|
||||
Hinnant and John Maddock.</p>
|
||||
|
||||
<p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John
|
||||
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
|
||||
discussion list at <a href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>.</p>
|
||||
|
||||
<p>.</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
@@ -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 <iostream>
|
||||
@@ -6,12 +16,7 @@
|
||||
#include <typeinfo>
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// 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
|
||||
|
||||
#include <boost/type_traits/type_traits_test.hpp>
|
||||
//
|
||||
// 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:
|
||||
@@ -93,18 +98,18 @@ std::pair<
|
||||
using namespace std;
|
||||
|
||||
//
|
||||
// struct checker:
|
||||
// struct call_traits_checker:
|
||||
// verifies behaviour of contained example:
|
||||
//
|
||||
template <class T>
|
||||
struct checker
|
||||
struct call_traits_checker
|
||||
{
|
||||
typedef typename boost::call_traits<T>::param_type param_type;
|
||||
void operator()(param_type);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void checker<T>::operator()(param_type p)
|
||||
void call_traits_checker<T>::operator()(param_type p)
|
||||
{
|
||||
T t(p);
|
||||
contained<T> c(t);
|
||||
@@ -112,18 +117,19 @@ void checker<T>::operator()(param_type p)
|
||||
assert(t == c.value());
|
||||
assert(t == c.get());
|
||||
assert(t == c.const_get());
|
||||
|
||||
cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
|
||||
#ifndef __ICL
|
||||
//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() << ">::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() << ">::call() is: " << typeid(&contained<T>::call).name() << endl;
|
||||
cout << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T, std::size_t N>
|
||||
struct checker<T[N]>
|
||||
struct call_traits_checker<T[N]>
|
||||
{
|
||||
typedef typename boost::call_traits<T[N]>::param_type param_type;
|
||||
void operator()(param_type t)
|
||||
@@ -171,57 +177,34 @@ void check_make_pair(T c, U u, V v)
|
||||
}
|
||||
|
||||
|
||||
struct UDT
|
||||
struct comparible_UDT
|
||||
{
|
||||
int i_;
|
||||
UDT() : i_(2){}
|
||||
bool operator == (const UDT& v){ return v.i_ == i_; }
|
||||
comparible_UDT() : i_(2){}
|
||||
bool operator == (const comparible_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(int argc, char *argv[ ])
|
||||
{
|
||||
checker<UDT> c1;
|
||||
UDT u;
|
||||
call_traits_checker<comparible_UDT> c1;
|
||||
comparible_UDT u;
|
||||
c1(u);
|
||||
checker<int> c2;
|
||||
call_traits_checker<int> c2;
|
||||
int i = 2;
|
||||
c2(i);
|
||||
int* pi = &i;
|
||||
checker<int*> c3;
|
||||
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||
call_traits_checker<int*> c3;
|
||||
c3(pi);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
checker<int&> c4;
|
||||
call_traits_checker<int&> c4;
|
||||
c4(i);
|
||||
checker<const int&> c5;
|
||||
call_traits_checker<const int&> c5;
|
||||
c5(i);
|
||||
|
||||
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
int a[2] = {1,2};
|
||||
checker<int[2]> c6;
|
||||
call_traits_checker<int[2]> c6;
|
||||
c6(a);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
check_wrap(wrap(2), 2);
|
||||
@@ -238,10 +221,10 @@ int main()
|
||||
typedef int& r_type;
|
||||
typedef const r_type cr_type;
|
||||
|
||||
type_test(UDT, boost::call_traits<UDT>::value_type)
|
||||
type_test(UDT&, boost::call_traits<UDT>::reference)
|
||||
type_test(const UDT&, boost::call_traits<UDT>::const_reference)
|
||||
type_test(const UDT&, boost::call_traits<UDT>::param_type)
|
||||
type_test(comparible_UDT, boost::call_traits<comparible_UDT>::value_type)
|
||||
type_test(comparible_UDT&, boost::call_traits<comparible_UDT>::reference)
|
||||
type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::const_reference)
|
||||
type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::param_type)
|
||||
type_test(int, boost::call_traits<int>::value_type)
|
||||
type_test(int&, boost::call_traits<int>::reference)
|
||||
type_test(const int&, boost::call_traits<int>::const_reference)
|
||||
@@ -250,7 +233,7 @@ int main()
|
||||
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*>::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&>::reference)
|
||||
type_test(const int&, boost::call_traits<int&>::const_reference)
|
||||
@@ -261,7 +244,7 @@ int main()
|
||||
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
||||
type_test(int&, boost::call_traits<cr_type>::param_type)
|
||||
#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;
|
||||
test_count += 4;
|
||||
#endif
|
||||
@@ -269,6 +252,7 @@ int main()
|
||||
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&>::param_type)
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
type_test(const int*, boost::call_traits<int[3]>::value_type)
|
||||
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
|
||||
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
|
||||
@@ -277,15 +261,18 @@ 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]>::const_reference)
|
||||
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
|
||||
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
|
||||
failures += 20;
|
||||
test_count += 20;
|
||||
#endif
|
||||
|
||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||
std::cin.get();
|
||||
return failures;
|
||||
return check_result(argc, argv);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -295,74 +282,99 @@ int main()
|
||||
template <typename T, bool isarray = false>
|
||||
struct call_traits_test
|
||||
{
|
||||
static void assert_construct(boost::call_traits<T>::param_type val);
|
||||
typedef ::boost::call_traits<T> ct;
|
||||
typedef typename ct::param_type param_type;
|
||||
typedef typename ct::reference reference;
|
||||
typedef typename ct::const_reference const_reference;
|
||||
typedef typename ct::value_type value_type;
|
||||
static void assert_construct(param_type val);
|
||||
};
|
||||
|
||||
template <typename T, bool isarray>
|
||||
void call_traits_test<T, isarray>::assert_construct(boost::call_traits<T>::param_type val)
|
||||
void call_traits_test<T, isarray>::assert_construct(typename call_traits_test<T, isarray>::param_type val)
|
||||
{
|
||||
//
|
||||
// this is to check that the call_traits assertions are valid:
|
||||
T t(val);
|
||||
boost::call_traits<T>::value_type v(t);
|
||||
boost::call_traits<T>::reference r(t);
|
||||
boost::call_traits<T>::const_reference cr(t);
|
||||
boost::call_traits<T>::param_type p(t);
|
||||
boost::call_traits<T>::value_type v2(v);
|
||||
boost::call_traits<T>::value_type v3(r);
|
||||
boost::call_traits<T>::value_type v4(p);
|
||||
boost::call_traits<T>::reference r2(v);
|
||||
boost::call_traits<T>::reference r3(r);
|
||||
boost::call_traits<T>::const_reference cr2(v);
|
||||
boost::call_traits<T>::const_reference cr3(r);
|
||||
boost::call_traits<T>::const_reference cr4(cr);
|
||||
boost::call_traits<T>::const_reference cr5(p);
|
||||
boost::call_traits<T>::param_type p2(v);
|
||||
boost::call_traits<T>::param_type p3(r);
|
||||
boost::call_traits<T>::param_type p4(p);
|
||||
value_type v(t);
|
||||
reference r(t);
|
||||
const_reference cr(t);
|
||||
param_type p(t);
|
||||
value_type v2(v);
|
||||
value_type v3(r);
|
||||
value_type v4(p);
|
||||
reference r2(v);
|
||||
reference r3(r);
|
||||
const_reference cr2(v);
|
||||
const_reference cr3(r);
|
||||
const_reference cr4(cr);
|
||||
const_reference cr5(p);
|
||||
param_type p2(v);
|
||||
param_type p3(r);
|
||||
param_type p4(p);
|
||||
}
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <typename T>
|
||||
struct call_traits_test<T, true>
|
||||
{
|
||||
static void assert_construct(boost::call_traits<T>::param_type val);
|
||||
typedef ::boost::call_traits<T> ct;
|
||||
typedef typename ct::param_type param_type;
|
||||
typedef typename ct::reference reference;
|
||||
typedef typename ct::const_reference const_reference;
|
||||
typedef typename ct::value_type value_type;
|
||||
static void assert_construct(param_type val);
|
||||
};
|
||||
|
||||
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:
|
||||
T t;
|
||||
boost::call_traits<T>::value_type v(t);
|
||||
boost::call_traits<T>::value_type v5(val);
|
||||
boost::call_traits<T>::reference r = t;
|
||||
boost::call_traits<T>::const_reference cr = t;
|
||||
boost::call_traits<T>::reference r2 = r;
|
||||
value_type v(t);
|
||||
value_type v5(val);
|
||||
reference r = t;
|
||||
const_reference cr = t;
|
||||
reference r2 = r;
|
||||
#ifndef __BORLANDC__
|
||||
// C++ Builder buglet:
|
||||
boost::call_traits<T>::const_reference cr2 = r;
|
||||
const_reference cr2 = r;
|
||||
#endif
|
||||
boost::call_traits<T>::param_type p(t);
|
||||
boost::call_traits<T>::value_type v2(v);
|
||||
boost::call_traits<T>::const_reference cr3 = cr;
|
||||
boost::call_traits<T>::value_type v3(r);
|
||||
boost::call_traits<T>::value_type v4(p);
|
||||
boost::call_traits<T>::param_type p2(v);
|
||||
boost::call_traits<T>::param_type p3(r);
|
||||
boost::call_traits<T>::param_type p4(p);
|
||||
param_type p(t);
|
||||
value_type v2(v);
|
||||
const_reference cr3 = cr;
|
||||
value_type v3(r);
|
||||
value_type v4(p);
|
||||
param_type p2(v);
|
||||
param_type p3(r);
|
||||
param_type p4(p);
|
||||
}
|
||||
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
//
|
||||
// now check call_traits assertions by instantiating call_traits_test:
|
||||
template struct call_traits_test<int>;
|
||||
template struct call_traits_test<const 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<const int&>;
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template struct call_traits_test<int[2], true>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
unsigned int expected_failures = 10;
|
||||
#elif defined(__SUNPRO_CC)
|
||||
unsigned int expected_failures = 11;
|
||||
#elif defined(__BORLANDC__)
|
||||
unsigned int expected_failures = 2;
|
||||
#elif defined(__GNUC__)
|
||||
unsigned int expected_failures = 4;
|
||||
#else
|
||||
unsigned int expected_failures = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
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
|
31
checked_delete_test.cpp
Normal file
31
checked_delete_test.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// Boost checked_delete test program ---------------------------------------//
|
||||
|
||||
// (C) Copyright Beman Dawes 2001. 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
|
||||
// 21 May 01 Initial version (Beman Dawes)
|
||||
|
||||
#include <boost/utility.hpp> // for checked_delete
|
||||
|
||||
// This program demonstrates compiler errors when trying to delete an
|
||||
// incomplete type.
|
||||
|
||||
namespace
|
||||
{
|
||||
class Incomplete;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Incomplete * p;
|
||||
boost::checked_delete(p); // should cause compile time error
|
||||
Incomplete ** pa;
|
||||
boost::checked_array_delete(pa); // should cause compile time error
|
||||
return 0;
|
||||
} // main
|
98
compressed_pair.htm
Normal file
98
compressed_pair.htm
Normal file
@@ -0,0 +1,98 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type"
|
||||
content="text/html; charset=iso-8859-1">
|
||||
<meta name="Template"
|
||||
content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
|
||||
<title>Header </title>
|
||||
<boost/compressed_pair.hpp>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
|
||||
vlink="#800080">
|
||||
|
||||
<h2><img src="../../c++boost.gif" width="276" height="86">Header
|
||||
<<a href="../../boost/detail/compressed_pair.hpp">boost/compressed_pair.hpp</a>></h2>
|
||||
|
||||
<p>All of the contents of <boost/compressed_pair.hpp> are
|
||||
defined inside namespace boost.</p>
|
||||
|
||||
<p>The class compressed pair is very similar to std::pair, but if
|
||||
either of the template arguments are empty classes, then the
|
||||
"empty member optimisation" is applied to compress the
|
||||
size of the pair.</p>
|
||||
|
||||
<pre>template <class T1, class T2>
|
||||
class compressed_pair
|
||||
{
|
||||
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() {}
|
||||
compressed_pair(first_param_type x, second_param_type y);
|
||||
explicit compressed_pair(first_param_type x);
|
||||
explicit compressed_pair(second_param_type y);
|
||||
|
||||
compressed_pair& operator=(const compressed_pair&);
|
||||
|
||||
first_reference first();
|
||||
first_const_reference first() const;
|
||||
|
||||
second_reference second();
|
||||
second_const_reference second() const;
|
||||
|
||||
void swap(compressed_pair& y);
|
||||
};</pre>
|
||||
|
||||
<p>The two members of the pair can be accessed using the member
|
||||
functions first() and second(). Note that not all member
|
||||
functions can be instantiated for all template parameter types.
|
||||
In particular compressed_pair can be instantiated for reference
|
||||
and array types, however in these cases the range of constructors
|
||||
that can be used are limited. If types T1 and T2 are the same
|
||||
type, then there is only one version of the single-argument
|
||||
constructor, and this constructor initialises both values in the
|
||||
pair to the passed value.</p>
|
||||
|
||||
<p>Note that compressed_pair can not be instantiated if either of
|
||||
the template arguments is a union type, unless there is compiler
|
||||
support for boost::is_union, or if boost::is_union is specialised
|
||||
for the union type.</p>
|
||||
|
||||
<p>Finally, a word of caution for Visual C++ 6 users: if either
|
||||
argument is an empty type, then assigning to that member will
|
||||
produce memory corruption, unless the empty type has a "do
|
||||
nothing" assignment operator defined. This is due to a bug
|
||||
in the way VC6 generates implicit assignment operators.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 08 May 2001</p>
|
||||
|
||||
<p><EFBFBD> Copyright boost.org 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>
|
||||
|
||||
<p>Based on contributions by Steve Cleary, Beman Dawes, Howard
|
||||
Hinnant and John Maddock.</p>
|
||||
|
||||
<p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John
|
||||
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
|
||||
discussion list at <a
|
||||
href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>.</p>
|
||||
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
@@ -1,51 +1,25 @@
|
||||
// boost::compressed_pair test program
|
||||
// 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.
|
||||
|
||||
// (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/compressed_pair.hpp>
|
||||
// Revised 03 Oct 2000:
|
||||
// Enabled tests for VC6.
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/compressed_pair.hpp>
|
||||
#include <boost/type_traits/type_traits_test.hpp>
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
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;}
|
||||
|
||||
#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_UDT
|
||||
{
|
||||
~empty_UDT(){};
|
||||
};
|
||||
namespace boost {
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
template <> struct is_empty<empty_UDT>
|
||||
@@ -64,76 +38,363 @@ template <> struct is_POD<empty_POD_UDT>
|
||||
#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; }
|
||||
};
|
||||
|
||||
int main()
|
||||
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; }
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
using std::swap;
|
||||
#endif
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_tester
|
||||
{
|
||||
compressed_pair<int, double> cp1(1, 1.3);
|
||||
assert(cp1.first() == 1);
|
||||
assert(cp1.second() == 1.3);
|
||||
compressed_pair<int, double> cp1b(2, 2.3);
|
||||
assert(cp1b.first() == 2);
|
||||
assert(cp1b.second() == 2.3);
|
||||
swap(cp1, cp1b);
|
||||
assert(cp1b.first() == 1);
|
||||
assert(cp1b.second() == 1.3);
|
||||
assert(cp1.first() == 2);
|
||||
assert(cp1.second() == 2.3);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
compressed_pair<empty_UDT, int> cp2(2);
|
||||
assert(cp2.second() == 2);
|
||||
#endif
|
||||
compressed_pair<int, empty_UDT> cp3(1);
|
||||
assert(cp3.first() ==1);
|
||||
compressed_pair<empty_UDT, empty_UDT> cp4;
|
||||
compressed_pair<empty_UDT, empty_POD_UDT> cp5;
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
int i = 0;
|
||||
compressed_pair<int&, int&> cp6(i,i);
|
||||
assert(cp6.first() == i);
|
||||
assert(cp6.second() == i);
|
||||
assert(&cp6.first() == &i);
|
||||
assert(&cp6.second() == &i);
|
||||
compressed_pair<int, double[2]> cp7;
|
||||
cp7.first();
|
||||
double* pd = cp7.second();
|
||||
#endif
|
||||
value_test(true, (sizeof(compressed_pair<empty_UDT, int>) < sizeof(std::pair<empty_UDT, int>)))
|
||||
value_test(true, (sizeof(compressed_pair<int, empty_UDT>) < sizeof(std::pair<int, empty_UDT>)))
|
||||
value_test(true, (sizeof(compressed_pair<empty_UDT, empty_UDT>) < sizeof(std::pair<empty_UDT, empty_UDT>)))
|
||||
value_test(true, (sizeof(compressed_pair<empty_UDT, empty_POD_UDT>) < sizeof(std::pair<empty_UDT, empty_POD_UDT>)))
|
||||
value_test(true, (sizeof(compressed_pair<empty_UDT, compressed_pair<empty_POD_UDT, int> >) < sizeof(std::pair<empty_UDT, std::pair<empty_POD_UDT, int> >)))
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||
std::cin.get();
|
||||
return failures;
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
// gcc 2.90 can't cope with function scope using
|
||||
// declarations, and generates an internal compiler error...
|
||||
using std::swap;
|
||||
#endif
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
// first param construct:
|
||||
boost::compressed_pair<T1,T2> cp2(p1);
|
||||
cp2.second() = p2;
|
||||
BOOST_TEST(cp2.first() == p1);
|
||||
BOOST_TEST(cp2.second() == p2);
|
||||
// second param construct:
|
||||
boost::compressed_pair<T1,T2> cp3(p2);
|
||||
cp3.first() = p1;
|
||||
BOOST_TEST(cp3.second() == p2);
|
||||
BOOST_TEST(cp3.first() == p1);
|
||||
// both param construct:
|
||||
boost::compressed_pair<T1,T2> cp4(p1, p2);
|
||||
BOOST_TEST(cp4.first() == p1);
|
||||
BOOST_TEST(cp4.second() == p2);
|
||||
boost::compressed_pair<T1,T2> cp5(p3, p4);
|
||||
BOOST_TEST(cp5.first() == p3);
|
||||
BOOST_TEST(cp5.second() == p4);
|
||||
// check const members:
|
||||
const boost::compressed_pair<T1,T2>& cpr1 = cp4;
|
||||
BOOST_TEST(cpr1.first() == p1);
|
||||
BOOST_TEST(cpr1.second() == p2);
|
||||
|
||||
// copy construct:
|
||||
boost::compressed_pair<T1,T2> cp6(cp4);
|
||||
BOOST_TEST(cp6.first() == p1);
|
||||
BOOST_TEST(cp6.second() == p2);
|
||||
// assignment:
|
||||
cp1 = cp4;
|
||||
BOOST_TEST(cp1.first() == p1);
|
||||
BOOST_TEST(cp1.second() == p2);
|
||||
cp1 = cp5;
|
||||
BOOST_TEST(cp1.first() == p3);
|
||||
BOOST_TEST(cp1.second() == p4);
|
||||
// swap:
|
||||
cp4.swap(cp5);
|
||||
BOOST_TEST(cp4.first() == p3);
|
||||
BOOST_TEST(cp4.second() == p4);
|
||||
BOOST_TEST(cp5.first() == p1);
|
||||
BOOST_TEST(cp5.second() == p2);
|
||||
swap(cp4,cp5);
|
||||
BOOST_TEST(cp4.first() == p1);
|
||||
BOOST_TEST(cp4.second() == p2);
|
||||
BOOST_TEST(cp5.first() == p3);
|
||||
BOOST_TEST(cp5.second() == p4);
|
||||
}
|
||||
|
||||
//
|
||||
// instanciate some compressed pairs:
|
||||
template class boost::compressed_pair<int, double>;
|
||||
template class boost::compressed_pair<int, int>;
|
||||
template class boost::compressed_pair<empty_UDT, int>;
|
||||
template class boost::compressed_pair<int, empty_UDT>;
|
||||
template class boost::compressed_pair<empty_UDT, empty_UDT>;
|
||||
template class boost::compressed_pair<empty_UDT, empty_POD_UDT>;
|
||||
// tests for case where one or both
|
||||
// parameters are reference types:
|
||||
//
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_reference_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
//
|
||||
// now some for which only a few specific members can be instantiated,
|
||||
// first references:
|
||||
template double& compressed_pair<double, int&>::first();
|
||||
template int& compressed_pair<double, int&>::second();
|
||||
template compressed_pair<double, int&>::compressed_pair(int&);
|
||||
template compressed_pair<double, int&>::compressed_pair(call_traits<double>::param_type,int&);
|
||||
//
|
||||
// and then arrays:
|
||||
#ifndef __BORLANDC__
|
||||
template call_traits<int[2]>::reference compressed_pair<double, int[2]>::second();
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_reference_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
// gcc 2.90 can't cope with function scope using
|
||||
// declarations, and generates an internal compiler error...
|
||||
using std::swap;
|
||||
#endif
|
||||
template call_traits<double>::reference compressed_pair<double, int[2]>::first();
|
||||
template compressed_pair<double, int[2]>::compressed_pair(const double&);
|
||||
template compressed_pair<double, int[2]>::compressed_pair();
|
||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// both param construct:
|
||||
boost::compressed_pair<T1,T2> cp4(p1, p2);
|
||||
BOOST_TEST(cp4.first() == p1);
|
||||
BOOST_TEST(cp4.second() == p2);
|
||||
boost::compressed_pair<T1,T2> cp5(p3, p4);
|
||||
BOOST_TEST(cp5.first() == p3);
|
||||
BOOST_TEST(cp5.second() == p4);
|
||||
// check const members:
|
||||
const boost::compressed_pair<T1,T2>& cpr1 = cp4;
|
||||
BOOST_TEST(cpr1.first() == p1);
|
||||
BOOST_TEST(cpr1.second() == p2);
|
||||
|
||||
// copy construct:
|
||||
boost::compressed_pair<T1,T2> cp6(cp4);
|
||||
BOOST_TEST(cp6.first() == p1);
|
||||
BOOST_TEST(cp6.second() == p2);
|
||||
// assignment:
|
||||
// VC6 bug:
|
||||
// When second() is an empty class, VC6 performs the
|
||||
// assignment by doing a memcpy - even though the empty
|
||||
// class is really a zero sized base class, the result
|
||||
// is that the memory of first() gets trampled over.
|
||||
// Similar arguments apply to the case that first() is
|
||||
// an empty base class.
|
||||
// Strangely the problem is dependent upon the compiler
|
||||
// settings - some generate the problem others do not.
|
||||
cp4.first() = p3;
|
||||
cp4.second() = p4;
|
||||
BOOST_TEST(cp4.first() == p3);
|
||||
BOOST_TEST(cp4.second() == p4);
|
||||
}
|
||||
//
|
||||
// supplimentary tests for case where first arg only is a reference type:
|
||||
//
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_reference1_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_reference1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// first param construct:
|
||||
boost::compressed_pair<T1,T2> cp2(p1);
|
||||
cp2.second() = p2;
|
||||
BOOST_TEST(cp2.first() == p1);
|
||||
BOOST_TEST(cp2.second() == p2);
|
||||
#endif
|
||||
}
|
||||
//
|
||||
// supplimentary tests for case where second arg only is a reference type:
|
||||
//
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_reference2_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_reference2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// second param construct:
|
||||
boost::compressed_pair<T1,T2> cp3(p2);
|
||||
cp3.first() = p1;
|
||||
BOOST_TEST(cp3.second() == p2);
|
||||
BOOST_TEST(cp3.first() == p1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// tests for where one or the other parameter is an array:
|
||||
//
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_array1_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
// second param construct:
|
||||
boost::compressed_pair<T1,T2> cp3(p2);
|
||||
cp3.first()[0] = p1[0];
|
||||
BOOST_TEST(cp3.second() == p2);
|
||||
BOOST_TEST(cp3.first()[0] == p1[0]);
|
||||
// check const members:
|
||||
const boost::compressed_pair<T1,T2>& cpr1 = cp3;
|
||||
BOOST_TEST(cpr1.first()[0] == p1[0]);
|
||||
BOOST_TEST(cpr1.second() == p2);
|
||||
|
||||
BOOST_TEST(sizeof(T1) == sizeof(cp1.first()));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_array2_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
// first param construct:
|
||||
boost::compressed_pair<T1,T2> cp2(p1);
|
||||
cp2.second()[0] = p2[0];
|
||||
BOOST_TEST(cp2.first() == p1);
|
||||
BOOST_TEST(cp2.second()[0] == p2[0]);
|
||||
// check const members:
|
||||
const boost::compressed_pair<T1,T2>& cpr1 = cp2;
|
||||
BOOST_TEST(cpr1.first() == p1);
|
||||
BOOST_TEST(cpr1.second()[0] == p2[0]);
|
||||
|
||||
BOOST_TEST(sizeof(T2) == sizeof(cp1.second()));
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_array_tester
|
||||
{
|
||||
// define the types we need:
|
||||
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;
|
||||
// define our test proc:
|
||||
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
cp1.first()[0] = p1[0];
|
||||
cp1.second()[0] = p2[0];
|
||||
BOOST_TEST(cp1.first()[0] == p1[0]);
|
||||
BOOST_TEST(cp1.second()[0] == p2[0]);
|
||||
// check const members:
|
||||
const boost::compressed_pair<T1,T2>& cpr1 = cp1;
|
||||
BOOST_TEST(cpr1.first()[0] == p1[0]);
|
||||
BOOST_TEST(cpr1.second()[0] == p2[0]);
|
||||
|
||||
BOOST_TEST(sizeof(T1) == sizeof(cp1.first()));
|
||||
BOOST_TEST(sizeof(T2) == sizeof(cp1.second()));
|
||||
}
|
||||
|
||||
int test_main(int argc, char *argv[ ])
|
||||
{
|
||||
// declare some variables to pass to the tester:
|
||||
non_empty1 ne1(2);
|
||||
non_empty1 ne2(3);
|
||||
non_empty2 ne3(4);
|
||||
non_empty2 ne4(5);
|
||||
empty_POD_UDT e1;
|
||||
empty_UDT e2;
|
||||
|
||||
// T1 != T2, both non-empty
|
||||
compressed_pair_tester<non_empty1,non_empty2>::test(ne1, ne3, ne2, ne4);
|
||||
// T1 != T2, T2 empty
|
||||
compressed_pair_tester<non_empty1,empty_POD_UDT>::test(ne1, e1, ne2, e1);
|
||||
// T1 != T2, T1 empty
|
||||
compressed_pair_tester<empty_POD_UDT,non_empty2>::test(e1, ne3, e1, ne4);
|
||||
// T1 != T2, both empty
|
||||
compressed_pair_tester<empty_POD_UDT,empty_UDT>::test(e1, e2, e1, e2);
|
||||
// T1 == T2, both non-empty
|
||||
compressed_pair_tester<non_empty1,non_empty1>::test(ne1, ne1, ne2, ne2);
|
||||
// T1 == T2, both empty
|
||||
compressed_pair_tester<empty_UDT,empty_UDT>::test(e2, e2, e2, e2);
|
||||
|
||||
|
||||
// test references:
|
||||
|
||||
// T1 != T2, both non-empty
|
||||
compressed_pair_reference_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4);
|
||||
compressed_pair_reference_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4);
|
||||
compressed_pair_reference1_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4);
|
||||
compressed_pair_reference2_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4);
|
||||
// T1 != T2, T2 empty
|
||||
compressed_pair_reference_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1);
|
||||
compressed_pair_reference1_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1);
|
||||
// T1 != T2, T1 empty
|
||||
compressed_pair_reference_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4);
|
||||
compressed_pair_reference2_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4);
|
||||
// T1 == T2, both non-empty
|
||||
compressed_pair_reference_tester<non_empty1&,non_empty1&>::test(ne1, ne1, ne2, ne2);
|
||||
|
||||
// tests arrays:
|
||||
non_empty1 nea1[2];
|
||||
non_empty1 nea2[2];
|
||||
non_empty2 nea3[2];
|
||||
non_empty2 nea4[2];
|
||||
nea1[0] = non_empty1(5);
|
||||
nea2[0] = non_empty1(6);
|
||||
nea3[0] = non_empty2(7);
|
||||
nea4[0] = non_empty2(8);
|
||||
|
||||
// T1 != T2, both non-empty
|
||||
compressed_pair_array1_tester<non_empty1[2],non_empty2>::test(nea1, ne3, nea2, ne4);
|
||||
compressed_pair_array2_tester<non_empty1,non_empty2[2]>::test(ne1, nea3, ne2, nea4);
|
||||
compressed_pair_array_tester<non_empty1[2],non_empty2[2]>::test(nea1, nea3, nea2, nea4);
|
||||
// T1 != T2, T2 empty
|
||||
compressed_pair_array1_tester<non_empty1[2],empty_POD_UDT>::test(nea1, e1, nea2, e1);
|
||||
// T1 != T2, T1 empty
|
||||
compressed_pair_array2_tester<empty_POD_UDT,non_empty2[2]>::test(e1, nea3, e1, nea4);
|
||||
// T1 == T2, both non-empty
|
||||
compressed_pair_array_tester<non_empty1[2],non_empty1[2]>::test(nea1, nea1, nea2, nea2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned int expected_failures = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
325
counting_iterator.htm
Normal file
325
counting_iterator.htm
Normal file
@@ -0,0 +1,325 @@
|
||||
<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>Counting Iterator Adaptor 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>Counting Iterator Adaptor</h1>
|
||||
|
||||
Defined in header
|
||||
<a href="../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a>
|
||||
|
||||
<p>
|
||||
How would you fill up a vector with the numbers zero
|
||||
through one hundred using <a
|
||||
href="http://www.sgi.com/tech/stl/copy.html"><tt>std::copy()</tt></a>? The
|
||||
only iterator operation missing from builtin integer types is an
|
||||
<tt>operator*()</tt> that returns the current
|
||||
value of the integer. The counting iterator adaptor adds this crucial piece of
|
||||
functionality to whatever type it wraps. One can use the
|
||||
counting iterator adaptor not only with integer types, but with any
|
||||
type that is <tt>Incrementable</tt> (see type requirements <a href="#requirements">below</a>). The
|
||||
following <b>pseudo-code</b> shows the general idea of how the
|
||||
counting iterator is implemented.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// inside a hypothetical counting_iterator class...
|
||||
typedef Incrementable value_type;
|
||||
value_type counting_iterator::operator*() const {
|
||||
return this->base; // no dereference!
|
||||
}
|
||||
</pre>
|
||||
|
||||
All of the other operators of the counting iterator behave in the same
|
||||
fashion as the <tt>Incrementable</tt> base type.
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class Incrementable>
|
||||
struct <a href="#counting_iterator_traits">counting_iterator_traits</a>;
|
||||
|
||||
template <class Incrementable>
|
||||
struct <a href="#counting_iterator_generator">counting_iterator_generator</a>;
|
||||
|
||||
template <class Incrementable>
|
||||
typename counting_iterator_generator<Incrementable>::type
|
||||
<a href="#make_counting_iterator">make_counting_iterator</a>(Incrementable x);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="counting_iterator_generator">The Counting Iterator Type
|
||||
Generator</a></h2>
|
||||
|
||||
The class template <tt>counting_iterator_generator<Incrementable></tt> is a <a href="../../more/generic_programming.html#type_generator">type generator</a> for counting iterators.
|
||||
|
||||
<pre>
|
||||
template <class Incrementable>
|
||||
class counting_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...> type;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this example we use the counting iterator generator to create a
|
||||
counting iterator, and count from zero to four.
|
||||
|
||||
<pre>
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <boost/counting_iterator.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
// Example of using counting_iterator_generator
|
||||
std::cout << "counting from 0 to 4:" << std::endl;
|
||||
boost::counting_iterator_generator<int>::type first(0), last(4);
|
||||
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output from this part is:
|
||||
<pre>
|
||||
counting from 0 to 4:
|
||||
0 1 2 3
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>Incrementable</tt></TD>
|
||||
<TD>The type being wrapped by the adaptor.</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
If the <tt>Incrementable</tt> type has all of the functionality of a
|
||||
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> except the <tt>operator*()</tt>, then the counting
|
||||
iterator will be a model of <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a>. If the <tt>Incrementable</tt> type has less
|
||||
functionality, then the counting iterator will have correspondingly
|
||||
less functionality.
|
||||
|
||||
<h3><a name="requirements">Type Requirements</a></h3>
|
||||
|
||||
The <tt>Incrementable</tt> type must be <a
|
||||
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default
|
||||
Constructible</a>, <a href="./CopyConstructible.html">Copy
|
||||
Constructible</a>, and <a href="./Assignable.html">Assignable</a>.
|
||||
Also, the <tt>Incrementable</tt> type must provide access to an
|
||||
associated <tt>difference_type</tt> and <tt>iterator_category</tt>
|
||||
through the <a
|
||||
href="#counting_iterator_traits"><tt>counting_iterator_traits</tt></a>
|
||||
class.
|
||||
|
||||
<p>
|
||||
Furthermore, if you wish to create a counting iterator that is a <a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward
|
||||
Iterator</a>, then the following expressions must be valid:
|
||||
<pre>
|
||||
Incrementable i, j;
|
||||
++i // pre-increment
|
||||
i == j // operator equal
|
||||
</pre>
|
||||
If you wish to create a counting iterator that is a <a
|
||||
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
|
||||
Bidirectional Iterator</a>, then pre-decrement is also required:
|
||||
<pre>
|
||||
--i
|
||||
</pre>
|
||||
If you wish to create a counting iterator that is a <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> Random
|
||||
Access Iterator</a>, then these additional expressions are also required:
|
||||
<pre>
|
||||
<a href="#counting_iterator_traits">counting_iterator_traits</a><Incrementable>::difference_type n;
|
||||
i += n
|
||||
n = i - j
|
||||
i < j
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The counting iterator type implements the member functions and
|
||||
operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> concept. In addition it has the following
|
||||
constructor:
|
||||
|
||||
<pre>
|
||||
counting_iterator_generator::type(const Incrementable& i)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
|
||||
<h2><a name="make_counting_iterator">The Counting Iterator Object Generator</a></h2>
|
||||
|
||||
<pre>
|
||||
template <class Incrementable>
|
||||
typename counting_iterator_generator<Incrementable>::type
|
||||
make_counting_iterator(Incrementable base);
|
||||
</pre>
|
||||
|
||||
An <a href="../../more/generic_programming.html#object_generator">object
|
||||
generator</a> function that provides a convenient way to create counting
|
||||
iterators.<p>
|
||||
|
||||
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this example we count from negative five to positive five, this
|
||||
time using the <tt>make_counting_iterator()</tt> function to save some
|
||||
typing.
|
||||
|
||||
<pre>
|
||||
// continuing from previous example...
|
||||
|
||||
std::cout << "counting from -5 to 4:" << std::endl;
|
||||
std::copy(boost::make_counting_iterator(-5),
|
||||
boost::make_counting_iterator(5),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output from this part is:
|
||||
<pre>
|
||||
counting from -5 to 4:
|
||||
-5 -4 -3 -2 -1 0 1 2 3 4
|
||||
</pre>
|
||||
|
||||
In the next example we create an array of numbers, and then create a
|
||||
second array of pointers, where each pointer is the address of a
|
||||
number in the first array. The counting iterator makes it easy to do
|
||||
this since dereferencing a counting iterator that is wrapping an
|
||||
iterator over the array of numbers just returns a pointer to the
|
||||
current location in the array. We then use the <a
|
||||
href="./indirect_iterator.htm">indirect iterator adaptor</a> to print
|
||||
out the number in the array by accessing the numbers through the array
|
||||
of pointers.
|
||||
|
||||
<pre>
|
||||
// continuing from previous example...
|
||||
|
||||
const int N = 7;
|
||||
std::vector<int> numbers;
|
||||
// Fill "numbers" array with [0,N)
|
||||
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
|
||||
std::back_inserter(numbers));
|
||||
|
||||
std::vector<std::vector<int>::iterator> pointers;
|
||||
|
||||
// Use counting iterator to fill in the array of pointers.
|
||||
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||
boost::make_counting_iterator(numbers.end()),
|
||||
std::back_inserter(pointers));
|
||||
|
||||
// Use indirect iterator to print out numbers by accessing
|
||||
// them through the array of pointers.
|
||||
std::cout << "indirectly printing out the numbers from 0 to "
|
||||
<< N << std::endl;
|
||||
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||
boost::make_indirect_iterator(pointers.end()),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
indirectly printing out the numbers from 0 to 7
|
||||
0 1 2 3 4 5 6
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="counting_iterator_traits">Counting Iterator Traits</a></h2>
|
||||
|
||||
The counting iterator adaptor needs to determine the appropriate
|
||||
<tt>difference_type</tt> and <tt>iterator_category</tt> to use based on the
|
||||
<tt>Incrementable</tt> type supplied by the user. The
|
||||
<tt>counting_iterator_traits</tt> class provides these types. If the
|
||||
<tt>Incrementable</tt> type is an integral type or an iterator, these types
|
||||
will be correctly deduced by the <tt>counting_iterator_traits</tt> provided by
|
||||
the library. Otherwise, the user must specialize
|
||||
<tt>counting_iterator_traits</tt> for her type or add nested typedefs to
|
||||
her type to fulfill the needs of
|
||||
<a href="http://www.sgi.com/tech/stl/iterator_traits.html">
|
||||
<tt>std::iterator_traits</tt></a>.
|
||||
|
||||
<p>The following pseudocode describes how the <tt>counting_iterator_traits</tt> are determined:
|
||||
|
||||
<pre>
|
||||
template <class Incrementable>
|
||||
struct counting_iterator_traits
|
||||
{
|
||||
if (numeric_limits<Incrementable>::is_specialized) {
|
||||
if (!numeric_limits<Incrementable>::is_integer)
|
||||
COMPILE_TIME_ERROR;
|
||||
|
||||
if (!numeric_limits<Incrementable>::is_bounded
|
||||
&& numeric_limits<Incrementable>::is_signed) {
|
||||
typedef Incrementable difference_type;
|
||||
}
|
||||
else if (numeric_limits<Incrementable>::is_integral) {
|
||||
typedef <i>next-larger-signed-type-or-intmax_t</i> difference_type;
|
||||
}
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
} else {
|
||||
typedef std::iterator_traits<Incrementable>::difference_type difference_type;
|
||||
typedef std::iterator_traits<Incrementable>::iterator_category iterator_category;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>The italicized sections above are implementation details, but it is important
|
||||
to know that the <tt>difference_type</tt> for integral types is selected so that
|
||||
it can always represent the difference between two values if such a built-in
|
||||
integer exists. On platforms with a working <tt>std::numeric_limits</tt>
|
||||
implementation, the <tt>difference_type</tt> for any variable-length signed
|
||||
integer type <tt>T</tt> is <tt>T</tt> itself.
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></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>
|
||||
<!-- LocalWords: html charset alt gif hpp incrementable const namespace htm
|
||||
-->
|
||||
<!-- LocalWords: struct typename iostream int Siek CopyConstructible pre
|
||||
-->
|
||||
|
53
counting_iterator_example.cpp
Normal file
53
counting_iterator_example.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <boost/counting_iterator.hpp>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
// Example of using counting_iterator_generator
|
||||
std::cout << "counting from 0 to 4:" << std::endl;
|
||||
boost::counting_iterator_generator<int>::type first(0), last(4);
|
||||
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using make_counting_iterator()
|
||||
std::cout << "counting from -5 to 4:" << std::endl;
|
||||
std::copy(boost::make_counting_iterator(-5),
|
||||
boost::make_counting_iterator(5),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using counting iterator to create an array of pointers.
|
||||
const int N = 7;
|
||||
std::vector<int> numbers;
|
||||
// Fill "numbers" array with [0,N)
|
||||
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
|
||||
std::back_inserter(numbers));
|
||||
|
||||
std::vector<std::vector<int>::iterator> pointers;
|
||||
|
||||
// Use counting iterator to fill in the array of pointers.
|
||||
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||
boost::make_counting_iterator(numbers.end()),
|
||||
std::back_inserter(pointers));
|
||||
|
||||
// Use indirect iterator to print out numbers by accessing
|
||||
// them through the array of pointers.
|
||||
std::cout << "indirectly printing out the numbers from 0 to "
|
||||
<< N << std::endl;
|
||||
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||
boost::make_indirect_iterator(pointers.end()),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
263
counting_iterator_test.cpp
Normal file
263
counting_iterator_test.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// (C) Copyright David Abrahams 2001. 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
|
||||
// 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with
|
||||
// plain MSVC again. (David Abrahams)
|
||||
// 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in
|
||||
// MSVC without STLport, so that the other tests may proceed
|
||||
// (David Abrahams)
|
||||
// 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams)
|
||||
// 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams)
|
||||
// 24 Jan 2001 Initial revision (David Abrahams)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(disable:4786) // identifier truncated in debug info
|
||||
#endif
|
||||
|
||||
#include <boost/pending/iterator_tests.hpp>
|
||||
#include <boost/counting_iterator.hpp>
|
||||
#include <boost/detail/iterator.hpp>
|
||||
#include <iostream>
|
||||
#include <climits>
|
||||
#include <iterator>
|
||||
#include <stdlib.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
# include <limits>
|
||||
#endif
|
||||
#ifndef BOOST_NO_SLIST
|
||||
# include <slist>
|
||||
#endif
|
||||
|
||||
template <class T> struct is_numeric
|
||||
{
|
||||
enum { value =
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
std::numeric_limits<T>::is_specialized
|
||||
#else
|
||||
// Causes warnings with GCC, but how else can I detect numeric types at
|
||||
// compile-time?
|
||||
(boost::is_convertible<int,T>::value &&
|
||||
boost::is_convertible<T,int>::value)
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// Special tests for RandomAccess CountingIterators.
|
||||
template <class CountingIterator>
|
||||
void category_test(
|
||||
CountingIterator start,
|
||||
CountingIterator finish,
|
||||
std::random_access_iterator_tag)
|
||||
{
|
||||
typedef typename
|
||||
boost::detail::iterator_traits<CountingIterator>::difference_type
|
||||
difference_type;
|
||||
difference_type distance = boost::detail::distance(start, finish);
|
||||
|
||||
// Pick a random position internal to the range
|
||||
difference_type offset = (unsigned)rand() % distance;
|
||||
assert(offset >= 0);
|
||||
CountingIterator internal = start;
|
||||
std::advance(internal, offset);
|
||||
|
||||
// Try some binary searches on the range to show that it's ordered
|
||||
assert(std::binary_search(start, finish, *internal));
|
||||
CountingIterator x,y;
|
||||
boost::tie(x,y) = std::equal_range(start, finish, *internal);
|
||||
assert(boost::detail::distance(x, y) == 1);
|
||||
|
||||
// Show that values outside the range can't be found
|
||||
assert(!std::binary_search(start, boost::prior(finish), *finish));
|
||||
|
||||
// Do the generic random_access_iterator_test
|
||||
typedef typename CountingIterator::value_type value_type;
|
||||
std::vector<value_type> v;
|
||||
for (value_type z = *start; z != *finish; ++z)
|
||||
v.push_back(z);
|
||||
if (v.size() >= 2)
|
||||
{
|
||||
// Note that this test requires a that the first argument is
|
||||
// dereferenceable /and/ a valid iterator prior to the first argument
|
||||
boost::random_access_iterator_test(start + 1, v.size() - 1, v.begin() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Special tests for bidirectional CountingIterators
|
||||
template <class CountingIterator>
|
||||
void category_test(CountingIterator start, CountingIterator finish, std::bidirectional_iterator_tag)
|
||||
{
|
||||
if (finish != start
|
||||
&& finish != boost::next(start)
|
||||
&& finish != boost::next(boost::next(start)))
|
||||
{
|
||||
// Note that this test requires a that the first argument is
|
||||
// dereferenceable /and/ a valid iterator prior to the first argument
|
||||
boost::bidirectional_iterator_test(boost::next(start), boost::next(*start), boost::next(boost::next(*start)));
|
||||
}
|
||||
}
|
||||
|
||||
template <class CountingIterator>
|
||||
void category_test(CountingIterator start, CountingIterator finish, std::forward_iterator_tag)
|
||||
{
|
||||
if (finish != start && finish != boost::next(start))
|
||||
boost::forward_iterator_test(start, *start, boost::next(*start));
|
||||
}
|
||||
|
||||
template <class CountingIterator>
|
||||
void test_aux(CountingIterator start, CountingIterator finish)
|
||||
{
|
||||
typedef typename CountingIterator::iterator_category category;
|
||||
typedef typename CountingIterator::value_type value_type;
|
||||
|
||||
// If it's a RandomAccessIterator we can do a few delicate tests
|
||||
category_test(start, finish, category());
|
||||
|
||||
// Okay, brute force...
|
||||
for (CountingIterator p = start; p != finish && boost::next(p) != finish; ++p)
|
||||
{
|
||||
assert(boost::next(*p) == *boost::next(p));
|
||||
}
|
||||
|
||||
// prove that a reference can be formed to these values
|
||||
typedef typename CountingIterator::value_type value;
|
||||
const value* q = &*start;
|
||||
(void)q; // suppress unused variable warning
|
||||
}
|
||||
|
||||
template <class Incrementable>
|
||||
void test(Incrementable start, Incrementable finish)
|
||||
{
|
||||
test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish));
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
void test_integer(Integer* = 0) // default arg works around MSVC bug
|
||||
{
|
||||
Integer start = 0;
|
||||
Integer finish = 120;
|
||||
test(start, finish);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void test_container(Container* = 0) // default arg works around MSVC bug
|
||||
{
|
||||
Container c(1 + (unsigned)rand() % 1673);
|
||||
|
||||
const typename Container::iterator start = c.begin();
|
||||
|
||||
// back off by 1 to leave room for dereferenceable value at the end
|
||||
typename Container::iterator finish = start;
|
||||
std::advance(finish, c.size() - 1);
|
||||
|
||||
test(start, finish);
|
||||
|
||||
typedef typename Container::const_iterator const_iterator;
|
||||
test(const_iterator(start), const_iterator(finish));
|
||||
}
|
||||
|
||||
class my_int1 {
|
||||
public:
|
||||
my_int1() { }
|
||||
my_int1(int x) : m_int(x) { }
|
||||
my_int1& operator++() { ++m_int; return *this; }
|
||||
bool operator==(const my_int1& x) const { return m_int == x.m_int; }
|
||||
private:
|
||||
int m_int;
|
||||
};
|
||||
|
||||
namespace boost {
|
||||
template <>
|
||||
struct counting_iterator_traits<my_int1> {
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
};
|
||||
}
|
||||
|
||||
class my_int2 {
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef void pointer;
|
||||
typedef void reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
my_int2() { }
|
||||
my_int2(int x) : m_int(x) { }
|
||||
my_int2& operator++() { ++m_int; return *this; }
|
||||
my_int2& operator--() { --m_int; return *this; }
|
||||
bool operator==(const my_int2& x) const { return m_int == x.m_int; }
|
||||
private:
|
||||
int m_int;
|
||||
};
|
||||
|
||||
class my_int3 {
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef void pointer;
|
||||
typedef void reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
|
||||
my_int3() { }
|
||||
my_int3(int x) : m_int(x) { }
|
||||
my_int3& operator++() { ++m_int; return *this; }
|
||||
my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; }
|
||||
std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; }
|
||||
my_int3& operator--() { --m_int; return *this; }
|
||||
bool operator==(const my_int3& x) const { return m_int == x.m_int; }
|
||||
bool operator!=(const my_int3& x) const { return m_int != x.m_int; }
|
||||
bool operator<(const my_int3& x) const { return m_int < x.m_int; }
|
||||
private:
|
||||
int m_int;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test the built-in integer types.
|
||||
test_integer<char>();
|
||||
test_integer<unsigned char>();
|
||||
test_integer<signed char>();
|
||||
test_integer<wchar_t>();
|
||||
test_integer<short>();
|
||||
test_integer<unsigned short>();
|
||||
test_integer<int>();
|
||||
test_integer<unsigned int>();
|
||||
test_integer<long>();
|
||||
test_integer<unsigned long>();
|
||||
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
|
||||
test_integer<long long>();
|
||||
test_integer<unsigned long long>();
|
||||
#endif
|
||||
|
||||
// wrapping an iterator or non-built-in integer type causes an INTERNAL
|
||||
// COMPILER ERROR in MSVC without STLport. I'm clueless as to why.
|
||||
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
|
||||
// Test user-defined type.
|
||||
test_integer<my_int1>();
|
||||
test_integer<my_int2>();
|
||||
test_integer<my_int3>();
|
||||
|
||||
// Some tests on container iterators, to prove we handle a few different categories
|
||||
test_container<std::vector<int> >();
|
||||
test_container<std::list<int> >();
|
||||
# ifndef BOOST_NO_SLIST
|
||||
test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
|
||||
# endif
|
||||
|
||||
// Also prove that we can handle raw pointers.
|
||||
int array[2000];
|
||||
test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1));
|
||||
#endif
|
||||
std::cout << "test successful " << std::endl;
|
||||
return 0;
|
||||
}
|
273
filter_iterator.htm
Normal file
273
filter_iterator.htm
Normal file
@@ -0,0 +1,273 @@
|
||||
<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>Filter Iterator Adaptor 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>Filter Iterator Adaptor</h1>
|
||||
|
||||
Defined in header
|
||||
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
|
||||
<p>
|
||||
The filter iterator adaptor creates a view of an iterator range in
|
||||
which some elements of the range are skipped over. A <a
|
||||
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>
|
||||
function object controls which elements are skipped. When the
|
||||
predicate is applied to an element, if it returns <tt>true</tt> then
|
||||
the element is retained and if it returns <tt>false</tt> then the
|
||||
element is skipped over.
|
||||
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class Predicate, class BaseIterator, ...>
|
||||
class filter_iterator_generator;
|
||||
|
||||
template <class Predicate, class BaseIterator>
|
||||
typename filter_iterator_generator<Predicate, BaseIterator>::type
|
||||
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate());
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="filter_iterator_generator">The Filter Iterator Type
|
||||
Generator</a></h2>
|
||||
|
||||
The class <tt>filter_iterator_generator</tt> is a helper class whose
|
||||
purpose is to construct a filter iterator type. The template
|
||||
parameters for this class are the <tt>Predicate</tt> function object
|
||||
type and the <tt>BaseIterator</tt> type that is being wrapped. In
|
||||
most cases the associated types for the wrapped iterator can be
|
||||
deduced from <tt>std::iterator_traits</tt>, but in some situations the
|
||||
user may want to override these types, so there are also template
|
||||
parameters for each of the iterator's associated types.
|
||||
|
||||
<pre>
|
||||
template <class Predicate, class BaseIterator,
|
||||
class Value, class Reference, class Pointer, class Category, class Distance>
|
||||
class filter_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting filter iterator type
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
The following example uses filter iterator to print out all the
|
||||
positive integers in an array.
|
||||
|
||||
<pre>
|
||||
struct is_positive_number {
|
||||
bool operator()(int x) { return 0 < x; }
|
||||
};
|
||||
int main() {
|
||||
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||
const int N = sizeof(numbers)/sizeof(int);
|
||||
|
||||
typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type FilterIter;
|
||||
is_positive_number predicate;
|
||||
FilterIter::policies_type policies(predicate, numbers + N);
|
||||
FilterIter filter_iter_first(numbers, policies);
|
||||
FilterIter filter_iter_last(numbers + N, policies);
|
||||
|
||||
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
4 5 8
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a href="http://www.sgi.com/tech/stl/Predicate.html"><tt>Predicate</tt></a></TD>
|
||||
<TD>The function object that determines which elements are retained and which elements are skipped.
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The iterator type being wrapped. This type must at least be a model
|
||||
of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>Value</tt></TD>
|
||||
<TD>The <tt>value_type</tt> of the resulting iterator,
|
||||
unless const. If const, a conforming compiler strips constness for the
|
||||
<tt>value_type</tt>. Typically the default for this parameter is the
|
||||
appropriate type<a href="#1">[1]</a>.<br> <b>Default:</b>
|
||||
<tt>std::iterator_traits<BaseIterator>::value_type</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>Reference</tt></TD>
|
||||
<TD>The <tt>reference</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator*()</tt>. Typically the default for
|
||||
this parameter is the appropriate type.<br> <b>Default:</b> If
|
||||
<tt>Value</tt> is supplied, <tt>Value&</tt> is used. Otherwise
|
||||
<tt>std::iterator_traits<BaseIterator>::reference</tt> is
|
||||
used.</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>Pointer</tt></TD>
|
||||
<TD>The <tt>pointer</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator->()</tt>.
|
||||
Typically the default for
|
||||
this parameter is the appropriate type.<br>
|
||||
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
|
||||
otherwise <tt>std::iterator_traits<BaseIterator>::pointer</tt>.</TD>
|
||||
</TR>
|
||||
|
||||
|
||||
<TR>
|
||||
<TD><tt>Category</tt></TD>
|
||||
<TD>The <tt>iterator_category</tt> type for the resulting iterator.
|
||||
Typically the
|
||||
default for this parameter is the appropriate type. If you override
|
||||
this parameter, do not use <tt>bidirectional_iterator_tag</tt>
|
||||
because filter iterators can not go in reverse.<br>
|
||||
<b>Default:</b> <tt>std::iterator_traits<BaseIterator>::iterator_category</tt></TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>Distance</tt></TD>
|
||||
<TD>The <tt>difference_type</tt> for the resulting iterator. Typically the default for
|
||||
this parameter is the appropriate type.<br>
|
||||
<b>Default:</b> <tt>std::iterator_traits<BaseIterator>::difference_type</TD>
|
||||
</TR>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
The filter iterator adaptor (the type
|
||||
<tt>filter_iterator_generator<...>::type</tt>) may be a model of <a
|
||||
href="http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> or <a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
|
||||
depending on the adapted iterator type.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The filter iterator type implements all of the member functions and
|
||||
operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
|
||||
concept. In addition it has the following constructor:
|
||||
|
||||
<pre>filter_iterator_generator::type(const BaseIterator& it, const Policies& p = Policies())</pre>
|
||||
|
||||
<p>
|
||||
The policies type has only one public function, which is its constructor:
|
||||
|
||||
<pre>filter_iterator_generator::policies_type(const Predicate& p, const BaseIterator& end)</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<h2><a name="make_filter_iterator">The Make Filter Iterator Function</a></h2>
|
||||
|
||||
<pre>
|
||||
template <class Predicate, class BaseIterator>
|
||||
typename detail::filter_generator<Predicate, BaseIterator>::type
|
||||
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate())
|
||||
</pre>
|
||||
|
||||
This function provides a convenient way to create filter iterators.
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this example we print out all numbers in the array that are
|
||||
greater than negative two.
|
||||
|
||||
<pre>
|
||||
int main()
|
||||
{
|
||||
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||
const int N = sizeof(numbers)/sizeof(int);
|
||||
|
||||
std::copy(boost::make_filter_iterator(numbers, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
boost::make_filter_iterator(numbers + N, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
}
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
0 -1 4 5 8
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In the next example we print the positive numbers using the
|
||||
<tt>make_filter_iterator()</tt> function.
|
||||
|
||||
<pre>
|
||||
struct is_positive_number {
|
||||
bool operator()(int x) { return 0 < x; }
|
||||
};
|
||||
int main()
|
||||
{
|
||||
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||
const int N = sizeof(numbers)/sizeof(int);
|
||||
|
||||
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
|
||||
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
4 5 8
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Notes</h3>
|
||||
|
||||
<a name="1">[1]</a> If the compiler does not support partial
|
||||
specialization and the wrapped iterator type is a builtin pointer then
|
||||
the <tt>Value</tt> type must be explicitly specified (don't use the
|
||||
default).
|
||||
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->09 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14894" --></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>
|
53
filter_iterator_example.cpp
Normal file
53
filter_iterator_example.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Example of using the filter iterator adaptor from
|
||||
// boost/iterator_adaptors.hpp.
|
||||
|
||||
// (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.
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
struct is_positive_number {
|
||||
bool operator()(int x) { return 0 < x; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||
const int N = sizeof(numbers)/sizeof(int);
|
||||
|
||||
// Example using make_filter_iterator()
|
||||
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
|
||||
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example using filter_iterator_generator
|
||||
typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type
|
||||
FilterIter;
|
||||
is_positive_number predicate;
|
||||
FilterIter::policies_type policies(predicate, numbers + N);
|
||||
FilterIter filter_iter_first(numbers, policies);
|
||||
FilterIter filter_iter_last(numbers + N, policies);
|
||||
|
||||
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Another example using make_filter_iterator()
|
||||
std::copy(boost::make_filter_iterator(numbers, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
boost::make_filter_iterator(numbers + N, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
41
fun_out_iter_example.cpp
Normal file
41
fun_out_iter_example.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// (C) Copyright Jeremy Siek 2001. 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.
|
||||
|
||||
// Revision History:
|
||||
|
||||
// 27 Feb 2001 Jeremy Siek
|
||||
// Initial checkin.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
struct string_appender {
|
||||
string_appender(std::string& s) : m_str(s) { }
|
||||
void operator()(const std::string& x) const {
|
||||
m_str += x;
|
||||
}
|
||||
std::string& m_str;
|
||||
};
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
std::vector<std::string> x;
|
||||
x.push_back("hello");
|
||||
x.push_back(" ");
|
||||
x.push_back("world");
|
||||
x.push_back("!");
|
||||
|
||||
std::string s = "";
|
||||
std::copy(x.begin(), x.end(),
|
||||
boost::make_function_output_iterator(string_appender(s)));
|
||||
|
||||
std::cout << s << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
169
function_output_iterator.htm
Normal file
169
function_output_iterator.htm
Normal file
@@ -0,0 +1,169 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
||||
<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>Function Output Iterator Adaptor 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>Function Output Iterator Adaptor</h1>
|
||||
Defined in header <a href=
|
||||
"../../boost/function_output_iterator.hpp">boost/function_output_iterator.hpp</a>
|
||||
|
||||
<p>The function output iterator adaptor makes it easier to create
|
||||
custom output iterators. The adaptor takes a <a
|
||||
href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
|
||||
Function</a> and creates a model of <a
|
||||
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
|
||||
Iterator</a>. Each item assigned to the output iterator is passed
|
||||
as an argument to the unary function. The motivation for this
|
||||
iterator is that creating a C++ Standard conforming output
|
||||
iterator is non-trivial, particularly because the proper
|
||||
implementation usually requires a proxy object. On the other hand,
|
||||
creating a function (or function object) is much simpler.
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class UnaryFunction>
|
||||
class function_output_iterator;
|
||||
|
||||
template <class UnaryFunction>
|
||||
function_output_iterator<UnaryFunction>
|
||||
make_function_output_iterator(const UnaryFunction& f = UnaryFunction())
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this example we create an output iterator that appends
|
||||
each item onto the end of a string, using the <tt>string_appender</tt>
|
||||
function.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
struct string_appender {
|
||||
string_appender(std::string& s) : m_str(s) { }
|
||||
void operator()(const std::string& x) const {
|
||||
m_str += x;
|
||||
}
|
||||
std::string& m_str;
|
||||
};
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
std::vector<std::string> x;
|
||||
x.push_back("hello");
|
||||
x.push_back(" ");
|
||||
x.push_back("world");
|
||||
x.push_back("!");
|
||||
|
||||
std::string s = "";
|
||||
std::copy(x.begin(), x.end(),
|
||||
boost::make_function_output_iterator(string_appender(s)));
|
||||
|
||||
std::cout << s << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="function_output_iterator">The Function Output Iterator Class</a></h2>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class UnaryFunction>
|
||||
class function_output_iterator;
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
The <tt>function_output_iterator</tt> class creates an <a
|
||||
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
|
||||
Iterator</a> out of a
|
||||
<a href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
|
||||
Function</a>. Each item assigned to the output iterator is passed
|
||||
as an argument to the unary function.
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<table border>
|
||||
<tr>
|
||||
<th>Parameter
|
||||
|
||||
<th>Description
|
||||
|
||||
<tr>
|
||||
<td><tt>UnaryFunction</tt>
|
||||
|
||||
<td>The function type being wrapped. The return type of the
|
||||
function is not used, so it can be <tt>void</tt>. The
|
||||
function must be a model of <a
|
||||
href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
|
||||
Function</a>.</td>
|
||||
</table>
|
||||
|
||||
<h3>Concept Model</h3>
|
||||
The function output iterator class is a model of <a
|
||||
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
|
||||
Iterator</a>.
|
||||
|
||||
<h2>Members</h3>
|
||||
The function output iterator implements the member functions
|
||||
and operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
|
||||
Iterator</a> concept. In addition it has the following constructor:
|
||||
<pre>
|
||||
explicit function_output_iterator(const UnaryFunction& f = UnaryFunction())
|
||||
</pre>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
<h2><a name="make_function_output_iterator">The Function Output Iterator Object
|
||||
Generator</a></h2>
|
||||
|
||||
The <tt>make_function_output_iterator()</tt> function provides a
|
||||
more convenient way to create function output iterator objects. The
|
||||
function saves the user the trouble of explicitly writing out the
|
||||
iterator types. If the default argument is used, the function
|
||||
type must be provided as an explicit template argument.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class UnaryFunction>
|
||||
function_output_iterator<UnaryFunction>
|
||||
make_function_output_iterator(const UnaryFunction& f = UnaryFunction())
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>© Copyright Jeremy Siek 2001. 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.
|
||||
|
||||
</body>
|
||||
</html>
|
366
half_open_range_test.cpp
Normal file
366
half_open_range_test.cpp
Normal file
@@ -0,0 +1,366 @@
|
||||
// (C) Copyright David Abrahams 2001. 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
|
||||
// 11 Feb 2001 Compile with Borland, re-enable failing tests (David Abrahams)
|
||||
// 29 Jan 2001 Initial revision (David Abrahams)
|
||||
|
||||
#include <boost/half_open_range.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <iterator>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
# include <limits>
|
||||
#endif
|
||||
#ifndef BOOST_NO_SLIST
|
||||
# include <slist>
|
||||
#endif
|
||||
|
||||
inline unsigned unsigned_random(unsigned max)
|
||||
{
|
||||
return (max > 0) ? (unsigned)rand() % max : 0;
|
||||
}
|
||||
|
||||
// Special tests for ranges supporting random access
|
||||
template <class T>
|
||||
void category_test_1(
|
||||
const boost::half_open_range<T>& r, std::random_access_iterator_tag)
|
||||
{
|
||||
typedef boost::half_open_range<T> range;
|
||||
typedef typename range::size_type size_type;
|
||||
size_type size = r.size();
|
||||
|
||||
// pick a random offset
|
||||
size_type offset = unsigned_random(size);
|
||||
|
||||
typename range::value_type x = *(r.begin() + offset);
|
||||
// test contains(value_type)
|
||||
assert(r.contains(r.start()) == !r.empty());
|
||||
assert(!r.contains(r.finish()));
|
||||
assert(r.contains(x) == (offset != size));
|
||||
|
||||
range::const_iterator p = r.find(x);
|
||||
assert((p == r.end()) == (x == r.finish()));
|
||||
assert(r.find(r.finish()) == r.end());
|
||||
|
||||
if (offset != size)
|
||||
{
|
||||
assert(x == r[offset]);
|
||||
assert(x == r.at(offset));
|
||||
}
|
||||
|
||||
bool caught_out_of_range = false;
|
||||
try {
|
||||
bool never_initialized = x == r.at(size);
|
||||
(void)never_initialized;
|
||||
}
|
||||
catch(std::out_of_range&)
|
||||
{
|
||||
caught_out_of_range = true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
assert(caught_out_of_range);
|
||||
}
|
||||
|
||||
// Those tests must be skipped for other ranges
|
||||
template <class T>
|
||||
void category_test_1(
|
||||
const boost::half_open_range<T>&, std::forward_iterator_tag)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned indices[][2] = { {0,0},{0,1},{0,2},{0,3},
|
||||
{1,1},{1,2},{1,3},
|
||||
{2,2},{2,3},
|
||||
{3,3}};
|
||||
|
||||
template <class Range>
|
||||
void category_test_2(
|
||||
const std::vector<Range>& ranges, unsigned i, unsigned j, std::random_access_iterator_tag)
|
||||
{
|
||||
typedef Range range;
|
||||
const range& ri = ranges[i];
|
||||
const range& rj = ranges[j];
|
||||
|
||||
if (indices[i][0] <= indices[j][0] && indices[i][1] >= indices[j][1])
|
||||
assert(ri.contains(rj));
|
||||
|
||||
if (ri.contains(rj))
|
||||
assert((ri & rj) == rj);
|
||||
assert(boost::intersects(ri, rj) == !(ri & rj).empty());
|
||||
|
||||
range t1(ri);
|
||||
t1 &= rj;
|
||||
assert(t1 == range(indices[i][0] > indices[j][0] ? ri.start() : rj.start(),
|
||||
indices[i][1] < indices[j][1] ? ri.finish() : rj.finish()));
|
||||
assert(t1 == (ri & rj));
|
||||
|
||||
range t2(ri);
|
||||
t2 |= rj;
|
||||
|
||||
if (ri.empty())
|
||||
assert(t2 == rj);
|
||||
else if (rj.empty())
|
||||
assert(t2 == ri);
|
||||
else
|
||||
assert(t2 == range(indices[i][0] < indices[j][0] ? ri.start() : rj.start(),
|
||||
indices[i][1] > indices[j][1] ? ri.finish() : rj.finish()));
|
||||
assert(t2 == (ri | rj));
|
||||
if (i == j)
|
||||
assert(ri == rj);
|
||||
|
||||
if (ri.empty() || rj.empty())
|
||||
assert((ri == rj) == (ri.empty() && rj.empty()));
|
||||
else
|
||||
assert((ri == rj) == (ri.start() == rj.start() && ri.finish() == rj.finish()));
|
||||
|
||||
assert((ri == rj) == !(ri != rj));
|
||||
|
||||
bool same = ri == rj;
|
||||
bool one_empty = ri.empty() != rj.empty();
|
||||
|
||||
std::less<range> less;
|
||||
std::less_equal<range> less_equal;
|
||||
std::greater<range> greater;
|
||||
std::greater_equal<range> greater_equal;
|
||||
|
||||
if (same)
|
||||
{
|
||||
assert(greater_equal(ri,rj));
|
||||
assert(less_equal(ri,rj));
|
||||
assert(!greater(ri,rj));
|
||||
assert(!less(ri,rj));
|
||||
}
|
||||
else if (one_empty)
|
||||
{
|
||||
const range& empty = ri.empty() ? ri : rj;
|
||||
const range& non_empty = rj.empty() ? ri : rj;
|
||||
|
||||
assert(less(empty,non_empty));
|
||||
assert(less_equal(empty,non_empty));
|
||||
assert(!greater(empty,non_empty));
|
||||
assert(!greater_equal(empty,non_empty));
|
||||
assert(!less(non_empty,empty));
|
||||
assert(!less_equal(non_empty,empty));
|
||||
assert(greater(non_empty,empty));
|
||||
assert(greater_equal(non_empty,empty));
|
||||
}
|
||||
else {
|
||||
if (indices[i][0] < indices[j][0] ||
|
||||
indices[i][0] == indices[j][0] && indices[i][1] < indices[j][1])
|
||||
{
|
||||
assert(!greater_equal(ri,rj));
|
||||
assert(less(ri,rj));
|
||||
}
|
||||
|
||||
if (indices[i][0] < indices[j][0] ||
|
||||
indices[i][0] == indices[j][0] && indices[i][1] <= indices[j][1])
|
||||
{
|
||||
assert(!greater(ri,rj));
|
||||
assert(less_equal(ri,rj));
|
||||
}
|
||||
|
||||
if (indices[i][0] > indices[j][0] ||
|
||||
indices[i][0] == indices[j][0] && indices[i][1] > indices[j][1])
|
||||
{
|
||||
assert(!less_equal(ri,rj));
|
||||
assert(greater(ri,rj));
|
||||
}
|
||||
|
||||
if (indices[i][0] > indices[j][0] ||
|
||||
indices[i][0] == indices[j][0] && indices[i][1] >= indices[j][1])
|
||||
{
|
||||
assert(!less(ri,rj));
|
||||
assert(greater_equal(ri,rj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Range>
|
||||
void category_test_2(
|
||||
const std::vector<Range>&, unsigned, unsigned, std::forward_iterator_tag)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void category_test_2(
|
||||
const std::vector<boost::half_open_range<T> >&, unsigned, unsigned, std::bidirectional_iterator_tag)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
void test_back(Range& x, std::bidirectional_iterator_tag)
|
||||
{
|
||||
assert(x.back() == boost::prior(x.finish()));
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
void test_back(Range& x, std::forward_iterator_tag)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
boost::half_open_range<T> range_identity(const boost::half_open_range<T>& x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test(T x0, T x1, T x2, T x3)
|
||||
{
|
||||
std::vector<boost::half_open_range<T> > ranges;
|
||||
typedef boost::half_open_range<T> range;
|
||||
|
||||
T bounds[4] = { x0, x1, x2, x3 };
|
||||
|
||||
const std::size_t num_ranges = sizeof(indices)/sizeof(*indices);
|
||||
// test construction
|
||||
for (std::size_t n = 0; n < num_ranges;++n)
|
||||
{
|
||||
T start = bounds[indices[n][0]];
|
||||
T finish = bounds[indices[n][1]];
|
||||
boost::half_open_range<T> r(start, finish);
|
||||
ranges.push_back(r);
|
||||
}
|
||||
|
||||
// test implicit conversion from std::pair<T,T>
|
||||
range converted = std::pair<T,T>(x0,x0);
|
||||
(void)converted;
|
||||
|
||||
// test assignment, equality and inequality
|
||||
range r00 = range(x0, x0);
|
||||
assert(r00 == range(x0,x0));
|
||||
assert(r00 == range(x1,x1)); // empty ranges are all equal
|
||||
if (x3 != x0)
|
||||
assert(r00 != range(x0, x3));
|
||||
r00 = range(x0, x3);
|
||||
assert(r00 == range(x0, x3));
|
||||
if (x3 != x0)
|
||||
assert(r00 != range(x0, x0));
|
||||
|
||||
typedef typename range::iterator iterator;
|
||||
typedef typename iterator::iterator_category category;
|
||||
|
||||
for (unsigned i = 0; i < num_ranges; ++i)
|
||||
{
|
||||
const range& r = ranges[i];
|
||||
|
||||
// test begin(), end(), basic iteration.
|
||||
unsigned count = 0;
|
||||
for (range::const_iterator p = r.begin(), finish = r.end();
|
||||
p != finish;
|
||||
++p, ++count)
|
||||
{
|
||||
assert(count < 2100);
|
||||
}
|
||||
|
||||
// test size(), empty(), front(), back()
|
||||
assert((unsigned)r.size() == count);
|
||||
if (indices[i][0] == indices[i][1])
|
||||
assert(r.empty());
|
||||
if (r.empty())
|
||||
assert(r.size() == 0);
|
||||
if (!r.empty())
|
||||
{
|
||||
assert(r.front() == r.start());
|
||||
test_back(r, category());
|
||||
}
|
||||
|
||||
// test swap
|
||||
range r1(r);
|
||||
range r2(x0,x3);
|
||||
const bool same = r1 == r2;
|
||||
r1.swap(r2);
|
||||
assert(r1 == range(x0,x3));
|
||||
assert(r2 == r);
|
||||
if (!same) {
|
||||
assert(r1 != r);
|
||||
assert(r2 != range(x0,x3));
|
||||
}
|
||||
|
||||
// do individual tests for random-access iterators
|
||||
category_test_1(r, category());
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < num_ranges; ++j) {
|
||||
for (unsigned k = 0; k < num_ranges; ++k) {
|
||||
category_test_2(ranges, j, k, category());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
void test_integer(Integer* = 0) // default arg works around MSVC bug
|
||||
{
|
||||
Integer a = 0;
|
||||
Integer b = a + unsigned_random(128 - a);
|
||||
Integer c = b + unsigned_random(128 - b);
|
||||
Integer d = c + unsigned_random(128 - c);
|
||||
|
||||
test(a, b, c, d);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void test_container(Container* = 0) // default arg works around MSVC bug
|
||||
{
|
||||
Container c(unsigned_random(1673));
|
||||
|
||||
const typename Container::size_type offset1 = unsigned_random(c.size());
|
||||
const typename Container::size_type offset2 = unsigned_random(c.size() - offset1);
|
||||
typename Container::iterator internal1 = c.begin();
|
||||
std::advance(internal1, offset1);
|
||||
typename Container::iterator internal2 = internal1;
|
||||
std::advance(internal2, offset2);
|
||||
|
||||
test(c.begin(), internal1, internal2, c.end());
|
||||
|
||||
typedef typename Container::const_iterator const_iterator;
|
||||
test(const_iterator(c.begin()),
|
||||
const_iterator(internal1),
|
||||
const_iterator(internal2),
|
||||
const_iterator(c.end()));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test the built-in integer types.
|
||||
test_integer<char>();
|
||||
test_integer<unsigned char>();
|
||||
test_integer<signed char>();
|
||||
test_integer<wchar_t>();
|
||||
test_integer<short>();
|
||||
test_integer<unsigned short>();
|
||||
test_integer<int>();
|
||||
test_integer<unsigned int>();
|
||||
test_integer<long>();
|
||||
test_integer<unsigned long>();
|
||||
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
|
||||
test_integer<long long>();
|
||||
test_integer<unsigned long long>();
|
||||
#endif
|
||||
// Some tests on container iterators, to prove we handle a few different categories
|
||||
test_container<std::vector<int> >();
|
||||
test_container<std::list<int> >();
|
||||
#ifndef BOOST_NO_SLIST
|
||||
test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
|
||||
#endif
|
||||
// Also prove that we can handle raw pointers.
|
||||
int array[2000];
|
||||
const std::size_t a = 0;
|
||||
const std::size_t b = a + unsigned_random(2000 - a);
|
||||
const std::size_t c = b + unsigned_random(2000 - b);
|
||||
test(array, array+b, array+c, array+2000);
|
||||
return 0;
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
// (C) Copyright Boost.org 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
// See boost/detail/call_traits.hpp and boost/detail/ob_call_traits.hpp
|
||||
// for full copyright notices.
|
||||
|
||||
#ifndef BOOST_CALL_TRAITS_HPP
|
||||
#define BOOST_CALL_TRAITS_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
#include <boost/detail/ob_call_traits.hpp>
|
||||
#else
|
||||
#include <boost/detail/call_traits.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_CALL_TRAITS_HPP
|
@@ -1,23 +0,0 @@
|
||||
// (C) Copyright Boost.org 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
// See boost/detail/compressed_pair.hpp and boost/detail/ob_compressed_pair.hpp
|
||||
// for full copyright notices.
|
||||
|
||||
#ifndef BOOST_COMPRESSED_PAIR_HPP
|
||||
#define BOOST_COMPRESSED_PAIR_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
#include <boost/detail/ob_compressed_pair.hpp>
|
||||
#else
|
||||
#include <boost/detail/compressed_pair.hpp>
|
||||
#endif
|
||||
|
||||
#endif // BOOST_COMPRESSED_PAIR_HPP
|
@@ -1,135 +0,0 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
/* Release notes:
|
||||
23rd July 2000:
|
||||
Fixed array specialization. (JM)
|
||||
Added Borland specific fixes for reference types
|
||||
(issue raised by Steve Cleary).
|
||||
*/
|
||||
|
||||
#ifndef BOOST_DETAIL_CALL_TRAITS_HPP
|
||||
#define BOOST_DETAIL_CALL_TRAITS_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <typename T, bool isp, bool b1, bool b2>
|
||||
struct ct_imp
|
||||
{
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
template <typename T, bool isp>
|
||||
struct ct_imp<T, isp, true, true>
|
||||
{
|
||||
typedef T const param_type;
|
||||
};
|
||||
|
||||
template <typename T, bool b1, bool b2>
|
||||
struct ct_imp<T, true, b1, b2>
|
||||
{
|
||||
typedef T const param_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
//
|
||||
// C++ Builder workaround: we should be able to define a compile time
|
||||
// constant and pass that as a single template parameter to ct_imp<T,bool>,
|
||||
// however compiler bugs prevent this - instead pass three bool's to
|
||||
// ct_imp<T,bool,bool,bool> and add an extra partial specialisation
|
||||
// of ct_imp to handle the logic. (JM)
|
||||
typedef typename detail::ct_imp<T, ::boost::is_pointer<typename remove_const<T>::type>::value, ::boost::is_arithmetic<typename remove_const<T>::type>::value, sizeof(T) <= sizeof(void*)>::param_type param_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct call_traits<T&>
|
||||
{
|
||||
typedef T& value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x550)
|
||||
// these are illegal specialisations; cv-qualifies applied to
|
||||
// references have no effect according to [8.3.2p1],
|
||||
// C++ Builder requires them though as it treats cv-qualified
|
||||
// references as distinct types...
|
||||
template <typename T>
|
||||
struct call_traits<T&const>
|
||||
{
|
||||
typedef T& value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
template <typename T>
|
||||
struct call_traits<T&volatile>
|
||||
{
|
||||
typedef T& value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
template <typename T>
|
||||
struct call_traits<T&const volatile>
|
||||
{
|
||||
typedef T& value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct call_traits<T [N]>
|
||||
{
|
||||
private:
|
||||
typedef T array_type[N];
|
||||
public:
|
||||
// degrades array to pointer:
|
||||
typedef const T* value_type;
|
||||
typedef array_type& reference;
|
||||
typedef const array_type& const_reference;
|
||||
typedef const T* const param_type;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct call_traits<const T [N]>
|
||||
{
|
||||
private:
|
||||
typedef const T array_type[N];
|
||||
public:
|
||||
// degrades array to pointer:
|
||||
typedef const T* value_type;
|
||||
typedef array_type& reference;
|
||||
typedef const array_type& const_reference;
|
||||
typedef const T* const param_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_DETAIL_CALL_TRAITS_HPP
|
@@ -1,420 +0,0 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
//
|
||||
// JM changes 25 Jan 2000:
|
||||
// Removed default arguments from compressed_pair_switch to get
|
||||
// C++ Builder 4 to accept them
|
||||
// rewriten swap to get gcc and C++ builder to compile.
|
||||
// added partial specialisations for case T1 == T2 to avoid duplicate constructor defs.
|
||||
|
||||
#ifndef BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
#define BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_CALL_TRAITS_HPP
|
||||
#include <boost/call_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// compressed_pair
|
||||
|
||||
namespace details
|
||||
{
|
||||
// JM altered 26 Jan 2000:
|
||||
template <class T1, class T2, bool IsSame, bool FirstEmpty, bool SecondEmpty>
|
||||
struct compressed_pair_switch;
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, false, false>
|
||||
{static const int value = 0;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, true, true>
|
||||
{static const int value = 3;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, true, false>
|
||||
{static const int value = 1;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, false, true>
|
||||
{static const int value = 2;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, true, true, true>
|
||||
{static const int value = 4;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, true, false, false>
|
||||
{static const int value = 5;};
|
||||
|
||||
template <class T1, class T2, int Version> class compressed_pair_imp;
|
||||
|
||||
#ifdef __GNUC__
|
||||
// workaround for GCC (JM):
|
||||
using std::swap;
|
||||
#endif
|
||||
//
|
||||
// can't call unqualified swap from within classname::swap
|
||||
// as Koenig lookup rules will find only the classname::swap
|
||||
// member function not the global declaration, so use cp_swap
|
||||
// as a forwarding function (JM):
|
||||
template <typename T>
|
||||
inline void cp_swap(T& t1, T& t2)
|
||||
{
|
||||
using std::swap;
|
||||
swap(t1, t2);
|
||||
}
|
||||
|
||||
// 0 derive from neither
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 0>
|
||||
{
|
||||
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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
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_imp& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
// 1 derive from T1
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 1>
|
||||
: private 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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
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_imp& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
// 2 derive from T2
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 2>
|
||||
: private 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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: second_type(y), first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
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_imp& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(first_, y.first_);
|
||||
}
|
||||
|
||||
private:
|
||||
first_type first_;
|
||||
};
|
||||
|
||||
// 3 derive from T1 and T2
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 3>
|
||||
: private T1,
|
||||
private 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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), second_type(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
first_const_reference first() const {return *this;}
|
||||
|
||||
second_reference second() {return *this;}
|
||||
second_const_reference second() const {return *this;}
|
||||
//
|
||||
// no need to swap empty bases:
|
||||
void swap(compressed_pair_imp&) {}
|
||||
};
|
||||
|
||||
// JM
|
||||
// 4 T1 == T2, T1 and T2 both empty
|
||||
// Note does not actually store an instance of T2 at all -
|
||||
// but reuses T1 base class for both first() and second().
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 4>
|
||||
: private 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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(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_imp&) {}
|
||||
private:
|
||||
};
|
||||
|
||||
// 5 T1 == T2 and are not empty: //JM
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 5>
|
||||
{
|
||||
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_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x), second_(x) {}
|
||||
|
||||
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_imp<T1, T2, 5>& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
} // details
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair
|
||||
: private ::boost::details::compressed_pair_imp<T1, T2,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T1,
|
||||
T2,
|
||||
::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
|
||||
::boost::is_empty<T1>::value,
|
||||
::boost::is_empty<T2>::value>::value>
|
||||
{
|
||||
private:
|
||||
typedef details::compressed_pair_imp<T1, T2,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T1,
|
||||
T2,
|
||||
::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
|
||||
::boost::is_empty<T1>::value,
|
||||
::boost::is_empty<T2>::value>::value> base;
|
||||
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() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
|
||||
explicit compressed_pair(first_param_type x) : base(x) {}
|
||||
explicit compressed_pair(second_param_type y) : base(y) {}
|
||||
|
||||
first_reference first() {return base::first();}
|
||||
first_const_reference first() const {return base::first();}
|
||||
|
||||
second_reference second() {return base::second();}
|
||||
second_const_reference second() const {return base::second();}
|
||||
|
||||
void swap(compressed_pair& y) { base::swap(y); }
|
||||
};
|
||||
|
||||
// JM
|
||||
// Partial specialisation for case where T1 == T2:
|
||||
//
|
||||
template <class T>
|
||||
class compressed_pair<T, T>
|
||||
: private details::compressed_pair_imp<T, T,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T,
|
||||
T,
|
||||
::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
|
||||
::boost::is_empty<T>::value,
|
||||
::boost::is_empty<T>::value>::value>
|
||||
{
|
||||
private:
|
||||
typedef details::compressed_pair_imp<T, T,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T,
|
||||
T,
|
||||
::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
|
||||
::boost::is_empty<T>::value,
|
||||
::boost::is_empty<T>::value>::value> base;
|
||||
public:
|
||||
typedef T first_type;
|
||||
typedef T 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() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
|
||||
explicit compressed_pair(first_param_type x) : base(x) {}
|
||||
|
||||
first_reference first() {return base::first();}
|
||||
first_const_reference first() const {return base::first();}
|
||||
|
||||
second_reference second() {return base::second();}
|
||||
second_const_reference second() const {return base::second();}
|
||||
|
||||
void swap(compressed_pair& y) { base::swap(y); }
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
inline
|
||||
void
|
||||
swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
|
||||
|
@@ -1,35 +0,0 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
//
|
||||
// Crippled version for crippled compilers:
|
||||
//
|
||||
#ifndef BOOST_OB_CALL_TRAITS_HPP
|
||||
#define BOOST_OB_CALL_TRAITS_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_OB_CALL_TRAITS_HPP
|
@@ -1,77 +0,0 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
//
|
||||
/* Release notes:
|
||||
23rd July 2000:
|
||||
Additional comments added. (JM)
|
||||
Jan 2000:
|
||||
Original version: this version crippled for use with crippled compilers
|
||||
- John Maddock Jan 2000.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BOOST_OB_COMPRESSED_PAIR_HPP
|
||||
#define BOOST_OB_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_CALL_TRAITS_HPP
|
||||
#include <boost/call_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair
|
||||
{
|
||||
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() : _first(), _second() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : _first(x), _second(y) {}
|
||||
explicit compressed_pair(first_param_type x) : _first(x), _second() {}
|
||||
// can't define this in case T1 == T2:
|
||||
// explicit compressed_pair(second_param_type y) : _first(), _second(y) {}
|
||||
|
||||
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& y)
|
||||
{
|
||||
using std::swap;
|
||||
swap(_first, y._first);
|
||||
swap(_second, y._second);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_OB_COMPRESSED_PAIR_HPP
|
||||
|
@@ -1,559 +0,0 @@
|
||||
// Boost operators.hpp header file ----------------------------------------//
|
||||
|
||||
// (C) Copyright David Abrahams 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.
|
||||
|
||||
// (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
|
||||
// 04 Jul 00 Fixed NO_OPERATORS_IN_NAMESPACE bugs, major cleanup and
|
||||
// refactoring of compiler workarounds, additional documentation
|
||||
// (Alexy Gurtovoy and Mark Rodgers with some help and prompting from
|
||||
// Dave Abrahams)
|
||||
// 28 Jun 00 General cleanup and integration of bugfixes from Mark Rodgers and
|
||||
// Jeremy Siek (Dave Abrahams)
|
||||
// 20 Jun 00 Changes to accommodate Borland C++Builder 4 and Borland C++ 5.5
|
||||
// (Mark Rodgers)
|
||||
// 20 Jun 00 Minor fixes to the prior revision (Aleksey Gurtovoy)
|
||||
// 10 Jun 00 Support for the base class chaining technique was added
|
||||
// (Aleksey Gurtovoy). See documentation and the comments below
|
||||
// for the details.
|
||||
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
|
||||
// 18 Nov 99 Change name "divideable" to "dividable", remove unnecessary
|
||||
// specializations of dividable, subtractable, modable (Ed Brey)
|
||||
// 17 Nov 99 Add comments (Beman Dawes)
|
||||
// Remove unnecessary specialization of operators<> (Ed Brey)
|
||||
// 15 Nov 99 Fix less_than_comparable<T,U> second operand type for first two
|
||||
// operators.(Beman Dawes)
|
||||
// 12 Nov 99 Add operators templates (Ed Brey)
|
||||
// 11 Nov 99 Add single template parameter version for compilers without
|
||||
// partial specialization (Beman Dawes)
|
||||
// 10 Nov 99 Initial version
|
||||
|
||||
// 10 Jun 00:
|
||||
// An additional optional template parameter was added to most of
|
||||
// operator templates to support the base class chaining technique (see
|
||||
// documentation for the details). Unfortunately, a straightforward
|
||||
// implementation of this change would have broken compatibility with the
|
||||
// previous version of the library by making it impossible to use the same
|
||||
// template name (e.g. 'addable') for both the 1- and 2-argument versions of
|
||||
// an operator template. This implementation solves the backward-compatibility
|
||||
// issue at the cost of some simplicity.
|
||||
//
|
||||
// One of the complications is an existence of special auxiliary class template
|
||||
// 'is_chained_base<>' (see 'detail' namespace below), which is used
|
||||
// to determine whether its template parameter is a library's operator template
|
||||
// or not. You have to specialize 'is_chained_base<>' for each new
|
||||
// operator template you add to the library.
|
||||
//
|
||||
// However, most of the non-trivial implementation details are hidden behind
|
||||
// several local macros defined below, and as soon as you understand them,
|
||||
// you understand the whole library implementation.
|
||||
|
||||
#ifndef BOOST_OPERATORS_HPP
|
||||
#define BOOST_OPERATORS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
|
||||
#if defined(__sgi) && !defined(__GNUC__)
|
||||
#pragma set woff 1234
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
|
||||
class empty_base {};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
// In this section we supply the xxxx1 and xxxx2 forms of the operator
|
||||
// templates, which are explicitly targeted at the 1-type-argument and
|
||||
// 2-type-argument operator forms, respectively. Some compilers get confused
|
||||
// when inline friend functions are overloaded in namespaces other than the
|
||||
// global namespace. When BOOST_NO_OPERATORS_IN_NAMESPACE is defined, all of
|
||||
// these templates must go in the global namespace.
|
||||
|
||||
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
namespace boost
|
||||
{
|
||||
#endif
|
||||
|
||||
// Basic operator classes (contributed by Dave Abrahams) ------------------//
|
||||
|
||||
// Note that friend functions defined in a class are implicitly inline.
|
||||
// See the C++ std, 11.4 [class.friend] paragraph 5
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct less_than_comparable2 : B
|
||||
{
|
||||
friend bool operator<=(const T& x, const U& y) { return !(x > y); }
|
||||
friend bool operator>=(const T& x, const U& y) { return !(x < y); }
|
||||
friend bool operator>(const U& x, const T& y) { return y < x; }
|
||||
friend bool operator<(const U& x, const T& y) { return y > x; }
|
||||
friend bool operator<=(const U& x, const T& y) { return !(y < x); }
|
||||
friend bool operator>=(const U& x, const T& y) { return !(y > x); }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct less_than_comparable1 : B
|
||||
{
|
||||
friend bool operator>(const T& x, const T& y) { return y < x; }
|
||||
friend bool operator<=(const T& x, const T& y) { return !(y < x); }
|
||||
friend bool operator>=(const T& x, const T& y) { return !(x < y); }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct equality_comparable2 : B
|
||||
{
|
||||
friend bool operator==(const U& y, const T& x) { return x == y; }
|
||||
friend bool operator!=(const U& y, const T& x) { return !(x == y); }
|
||||
friend bool operator!=(const T& y, const U& x) { return !(y == x); }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct equality_comparable1 : B
|
||||
{
|
||||
friend bool operator!=(const T& x, const T& y) { return !(x == y); }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct multipliable2 : B
|
||||
{
|
||||
friend T operator*(T x, const U& y) { return x *= y; }
|
||||
friend T operator*(const U& y, T x) { return x *= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct multipliable1 : B
|
||||
{
|
||||
friend T operator*(T x, const T& y) { return x *= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct addable2 : B
|
||||
{
|
||||
friend T operator+(T x, const U& y) { return x += y; }
|
||||
friend T operator+(const U& y, T x) { return x += y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct addable1 : B
|
||||
{
|
||||
friend T operator+(T x, const T& y) { return x += y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct subtractable2 : B
|
||||
{
|
||||
friend T operator-(T x, const U& y) { return x -= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct subtractable1 : B
|
||||
{
|
||||
friend T operator-(T x, const T& y) { return x -= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct dividable2 : B
|
||||
{
|
||||
friend T operator/(T x, const U& y) { return x /= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct dividable1 : B
|
||||
{
|
||||
friend T operator/(T x, const T& y) { return x /= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct modable2 : B
|
||||
{
|
||||
friend T operator%(T x, const U& y) { return x %= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct modable1 : B
|
||||
{
|
||||
friend T operator%(T x, const T& y) { return x %= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct xorable2 : B
|
||||
{
|
||||
friend T operator^(T x, const U& y) { return x ^= y; }
|
||||
friend T operator^(const U& y, T x) { return x ^= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct xorable1 : B
|
||||
{
|
||||
friend T operator^(T x, const T& y) { return x ^= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct andable2 : B
|
||||
{
|
||||
friend T operator&(T x, const U& y) { return x &= y; }
|
||||
friend T operator&(const U& y, T x) { return x &= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct andable1 : B
|
||||
{
|
||||
friend T operator&(T x, const T& y) { return x &= y; }
|
||||
};
|
||||
|
||||
template <class T, class U, class B = ::boost::detail::empty_base>
|
||||
struct orable2 : B
|
||||
{
|
||||
friend T operator|(T x, const U& y) { return x |= y; }
|
||||
friend T operator|(const U& y, T x) { return x |= y; }
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct orable1 : B
|
||||
{
|
||||
friend T operator|(T x, const T& y) { return x |= y; }
|
||||
};
|
||||
|
||||
// incrementable and decrementable contributed by Jeremy Siek
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct incrementable : B
|
||||
{
|
||||
friend T operator++(T& x, int)
|
||||
{
|
||||
incrementable_type tmp(x);
|
||||
++x;
|
||||
return tmp;
|
||||
}
|
||||
private: // The use of this typedef works around a Borland bug
|
||||
typedef T incrementable_type;
|
||||
};
|
||||
|
||||
template <class T, class B = ::boost::detail::empty_base>
|
||||
struct decrementable : B
|
||||
{
|
||||
friend T operator--(T& x, int)
|
||||
{
|
||||
decrementable_type tmp(x);
|
||||
--x;
|
||||
return tmp;
|
||||
}
|
||||
private: // The use of this typedef works around a Borland bug
|
||||
typedef T decrementable_type;
|
||||
};
|
||||
|
||||
// Iterator operator classes (contributed by Jeremy Siek) ------------------//
|
||||
|
||||
template <class T, class P, class B = ::boost::detail::empty_base>
|
||||
struct dereferenceable : B
|
||||
{
|
||||
P operator->() const
|
||||
{
|
||||
return &*static_cast<const T&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class I, class R, class B = ::boost::detail::empty_base>
|
||||
struct indexable : B
|
||||
{
|
||||
R operator[](I n) const
|
||||
{
|
||||
return *(static_cast<const T&>(*this) + n);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
} // namespace boost
|
||||
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
|
||||
|
||||
// BOOST_IMPORT_TEMPLATE1/BOOST_IMPORT_TEMPLATE2 -
|
||||
//
|
||||
// When BOOST_NO_OPERATORS_IN_NAMESPACE is defined we need a way to import an
|
||||
// operator template into the boost namespace. BOOST_IMPORT_TEMPLATE1 is used
|
||||
// for one-argument forms of operator templates; BOOST_IMPORT_TEMPLATE2 for
|
||||
// two-argument forms. Note that these macros expect to be invoked from within
|
||||
// boost.
|
||||
|
||||
#if defined(BOOST_NO_OPERATORS_IN_NAMESPACE)
|
||||
|
||||
# if defined(BOOST_NO_USING_TEMPLATE)
|
||||
|
||||
// Because a Borland C++ 5.5 bug prevents a using declaration from working,
|
||||
// we are forced to use inheritance for that compiler.
|
||||
# define BOOST_IMPORT_TEMPLATE2(template_name) \
|
||||
template <class T, class U, class B = ::boost::detail::empty_base> \
|
||||
struct template_name : ::template_name<T, U, B> {};
|
||||
|
||||
# define BOOST_IMPORT_TEMPLATE1(template_name) \
|
||||
template <class T, class B = ::boost::detail::empty_base> \
|
||||
struct template_name : ::template_name<T, B> {};
|
||||
|
||||
# else
|
||||
|
||||
// Otherwise, bring the names in with a using-declaration to avoid
|
||||
// stressing the compiler
|
||||
# define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name;
|
||||
# define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name;
|
||||
|
||||
# endif // BOOST_NO_USING_TEMPLATE
|
||||
|
||||
#else // !BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
|
||||
// The template is already in boost so we have nothing to do.
|
||||
# define BOOST_IMPORT_TEMPLATE2(template_name)
|
||||
# define BOOST_IMPORT_TEMPLATE1(template_name)
|
||||
|
||||
#endif // BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
|
||||
//
|
||||
// Here's where we put it all together, defining the xxxx forms of the templates
|
||||
// in namespace boost. We also define specializations of is_chained_base<> for
|
||||
// the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as
|
||||
// neccessary.
|
||||
//
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
// is_chained_base<> - a traits class used to distinguish whether an operator
|
||||
// template argument is being used for base class chaining, or is specifying a
|
||||
// 2nd argument type.
|
||||
|
||||
namespace boost {
|
||||
// A type parameter is used instead of a plain bool because Borland's compiler
|
||||
// didn't cope well with the more obvious non-type template parameter.
|
||||
namespace detail {
|
||||
struct true_t {};
|
||||
struct false_t {};
|
||||
} // namespace detail
|
||||
|
||||
// Unspecialized version assumes that most types are not being used for base
|
||||
// class chaining. We specialize for the operator templates defined in this
|
||||
// library.
|
||||
template<class T> struct is_chained_base {
|
||||
typedef ::boost::detail::false_t value;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
// Import a 2-type-argument operator template into boost (if neccessary) and
|
||||
// provide a specialization of 'is_chained_base<>' for it.
|
||||
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \
|
||||
BOOST_IMPORT_TEMPLATE2(template_name2) \
|
||||
template<class T, class U, class B> \
|
||||
struct is_chained_base< ::boost::template_name2<T, U, B> > { \
|
||||
typedef ::boost::detail::true_t value; \
|
||||
};
|
||||
|
||||
// Import a 1-type-argument operator template into boost (if neccessary) and
|
||||
// provide a specialization of 'is_chained_base<>' for it.
|
||||
# define BOOST_OPERATOR_TEMPLATE1(template_name1) \
|
||||
BOOST_IMPORT_TEMPLATE1(template_name1) \
|
||||
template<class T, class B> \
|
||||
struct is_chained_base< ::boost::template_name1<T, B> > { \
|
||||
typedef ::boost::detail::true_t value; \
|
||||
};
|
||||
|
||||
// BOOST_OPERATOR_TEMPLATE(template_name) defines template_name<> such that it
|
||||
// can be used for specifying both 1-argument and 2-argument forms. Requires the
|
||||
// existence of two previously defined class templates named '<template_name>1'
|
||||
// and '<template_name>2' which must implement the corresponding 1- and 2-
|
||||
// argument forms.
|
||||
//
|
||||
// The template type parameter O == is_chained_base<U>::value is used to
|
||||
// distinguish whether the 2nd argument to <template_name> is being used for
|
||||
// base class chaining from another boost operator template or is describing a
|
||||
// 2nd operand type. O == true_t only when U is actually an another operator
|
||||
// template from the library. Partial specialization is used to select an
|
||||
// implementation in terms of either '<template_name>1' or '<template_name>2'.
|
||||
//
|
||||
|
||||
# define BOOST_OPERATOR_TEMPLATE(template_name) \
|
||||
template <class T \
|
||||
,class U = T \
|
||||
,class B = ::boost::detail::empty_base \
|
||||
,class O = typename is_chained_base<U>::value \
|
||||
> \
|
||||
struct template_name : template_name##2<T, U, B> {}; \
|
||||
\
|
||||
template<class T, class U, class B> \
|
||||
struct template_name<T, U, B, ::boost::detail::true_t> \
|
||||
: template_name##1<T, U> {}; \
|
||||
\
|
||||
template <class T, class B> \
|
||||
struct template_name<T, T, B, ::boost::detail::false_t> \
|
||||
: template_name##1<T, B> {}; \
|
||||
\
|
||||
template<class T, class U, class B, class O> \
|
||||
struct is_chained_base< ::boost::template_name<T, U, B, O> > { \
|
||||
typedef ::boost::detail::true_t value; \
|
||||
}; \
|
||||
\
|
||||
BOOST_OPERATOR_TEMPLATE2(template_name##2) \
|
||||
BOOST_OPERATOR_TEMPLATE1(template_name##1)
|
||||
|
||||
|
||||
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
# define BOOST_OPERATOR_TEMPLATE2(template_name2) \
|
||||
BOOST_IMPORT_TEMPLATE2(template_name2)
|
||||
# define BOOST_OPERATOR_TEMPLATE1(template_name1) \
|
||||
BOOST_IMPORT_TEMPLATE1(template_name1)
|
||||
|
||||
// In this case we can only assume that template_name<> is equivalent to the
|
||||
// more commonly needed template_name1<> form.
|
||||
# define BOOST_OPERATOR_TEMPLATE(template_name) \
|
||||
template <class T, class B = ::boost::detail::empty_base> \
|
||||
struct template_name : template_name##1<T, B> {};
|
||||
|
||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_OPERATOR_TEMPLATE(less_than_comparable)
|
||||
BOOST_OPERATOR_TEMPLATE(equality_comparable)
|
||||
BOOST_OPERATOR_TEMPLATE(multipliable)
|
||||
BOOST_OPERATOR_TEMPLATE(addable)
|
||||
BOOST_OPERATOR_TEMPLATE(subtractable)
|
||||
BOOST_OPERATOR_TEMPLATE(dividable)
|
||||
BOOST_OPERATOR_TEMPLATE(modable)
|
||||
BOOST_OPERATOR_TEMPLATE(xorable)
|
||||
BOOST_OPERATOR_TEMPLATE(andable)
|
||||
BOOST_OPERATOR_TEMPLATE(orable)
|
||||
|
||||
BOOST_OPERATOR_TEMPLATE1(incrementable)
|
||||
BOOST_OPERATOR_TEMPLATE1(decrementable)
|
||||
BOOST_OPERATOR_TEMPLATE2(dereferenceable)
|
||||
|
||||
// indexable doesn't follow the patterns above (it has 4 template arguments), so
|
||||
// we just write out the compiler hacks explicitly.
|
||||
#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE
|
||||
# ifdef BOOST_NO_USING_TEMPLATE
|
||||
template <class T, class I, class R, class B = ::boost::detail::empty_base>
|
||||
struct indexable : ::indexable<T,I,R,B> {};
|
||||
# else
|
||||
using ::indexable;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T, class I, class R, class B>
|
||||
struct is_chained_base< ::boost::indexable<T, I, R, B> > {
|
||||
typedef ::boost::detail::true_t operator_template_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
#undef BOOST_OPERATOR_TEMPLATE
|
||||
#undef BOOST_OPERATOR_TEMPLATE2
|
||||
#undef BOOST_OPERATOR_TEMPLATE1
|
||||
#undef BOOST_IMPORT_TEMPLATE1
|
||||
#undef BOOST_IMPORT_TEMPLATE2
|
||||
|
||||
// The following 'operators' classes can only be used portably if the derived class
|
||||
// declares ALL of the required member operators.
|
||||
template <class T, class U>
|
||||
struct operators2
|
||||
: less_than_comparable2<T,U
|
||||
, equality_comparable2<T,U
|
||||
, addable2<T,U
|
||||
, subtractable2<T,U
|
||||
, multipliable2<T,U
|
||||
, dividable2<T,U
|
||||
, modable2<T,U
|
||||
, orable2<T,U
|
||||
, andable2<T,U
|
||||
, xorable2<T,U
|
||||
> > > > > > > > > > {};
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T, class U = T>
|
||||
struct operators : operators2<T, U> {};
|
||||
|
||||
template <class T> struct operators<T, T>
|
||||
#else
|
||||
template <class T> struct operators
|
||||
#endif
|
||||
: less_than_comparable<T
|
||||
, equality_comparable<T
|
||||
, addable<T
|
||||
, subtractable<T
|
||||
, multipliable<T
|
||||
, dividable<T
|
||||
, modable<T
|
||||
, orable<T
|
||||
, andable<T
|
||||
, xorable<T
|
||||
, incrementable<T
|
||||
, decrementable<T
|
||||
> > > > > > > > > > > > {};
|
||||
|
||||
// Iterator helper classes (contributed by Jeremy Siek) -------------------//
|
||||
template <class T,
|
||||
class V,
|
||||
class D = std::ptrdiff_t,
|
||||
class P = V*,
|
||||
class R = V&>
|
||||
struct forward_iterator_helper
|
||||
: equality_comparable<T
|
||||
, incrementable<T
|
||||
, dereferenceable<T,P
|
||||
, boost::iterator<std::forward_iterator_tag, V, D
|
||||
> > > > {};
|
||||
|
||||
template <class T,
|
||||
class V,
|
||||
class D = std::ptrdiff_t,
|
||||
class P = V*,
|
||||
class R = V&>
|
||||
struct bidirectional_iterator_helper
|
||||
: equality_comparable<T
|
||||
, incrementable<T
|
||||
, decrementable<T
|
||||
, dereferenceable<T,P
|
||||
, boost::iterator<std::bidirectional_iterator_tag, V, D
|
||||
> > > > > {};
|
||||
|
||||
template <class T,
|
||||
class V,
|
||||
class D = std::ptrdiff_t,
|
||||
class P = V*,
|
||||
class R = V&>
|
||||
struct random_access_iterator_helper
|
||||
: equality_comparable<T
|
||||
, less_than_comparable<T
|
||||
, incrementable<T
|
||||
, decrementable<T
|
||||
, dereferenceable<T,P
|
||||
, addable2<T,D
|
||||
, subtractable2<T,D
|
||||
, indexable<T,D,R
|
||||
, boost::iterator<std::random_access_iterator_tag, V, D
|
||||
> > > > > > > > >
|
||||
{
|
||||
#ifndef __BORLANDC__
|
||||
friend D requires_difference_operator(const T& x, const T& y) {
|
||||
return x - y;
|
||||
}
|
||||
#endif
|
||||
}; // random_access_iterator_helper
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#if defined(__sgi) && !defined(__GNUC__)
|
||||
#pragma reset woff 1234
|
||||
#endif
|
||||
|
||||
#endif // BOOST_OPERATORS_HPP
|
@@ -1,69 +0,0 @@
|
||||
// boost utility.hpp header file -------------------------------------------//
|
||||
|
||||
// (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.
|
||||
|
||||
// Classes appear in alphabetical order
|
||||
|
||||
// Revision History
|
||||
// 26 Jan 00 protected noncopyable destructor added (Miki Jovanovic)
|
||||
// 10 Dec 99 next() and prior() templates added (Dave Abrahams)
|
||||
// 30 Aug 99 moved cast templates to cast.hpp (Beman Dawes)
|
||||
// 3 Aug 99 cast templates added
|
||||
// 20 Jul 99 name changed to utility.hpp
|
||||
// 9 Jun 99 protected noncopyable default ctor
|
||||
// 2 Jun 99 Initial Version. Class noncopyable only contents (Dave Abrahams)
|
||||
|
||||
#ifndef BOOST_UTILITY_HPP
|
||||
#define BOOST_UTILITY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <cstddef> // for size_t
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// next() and prior() template functions -----------------------------------//
|
||||
|
||||
// Helper functions for classes like bidirectional iterators not supporting
|
||||
// operator+ and operator-.
|
||||
//
|
||||
// Usage:
|
||||
// const std::list<T>::iterator p = get_some_iterator();
|
||||
// const std::list<T>::iterator prev = boost::prior(p);
|
||||
|
||||
// Contributed by Dave Abrahams
|
||||
|
||||
template <class T>
|
||||
T next(T x) { return ++x; }
|
||||
|
||||
template <class T>
|
||||
T prior(T x) { return --x; }
|
||||
|
||||
|
||||
// class noncopyable -------------------------------------------------------//
|
||||
|
||||
// Private copy constructor and copy assignment ensure classes derived from
|
||||
// class noncopyable cannot be copied.
|
||||
|
||||
// Contributed by Dave Abrahams
|
||||
|
||||
class noncopyable
|
||||
{
|
||||
protected:
|
||||
noncopyable(){}
|
||||
~noncopyable(){}
|
||||
private: // emphasize the following members are private
|
||||
noncopyable( const noncopyable& );
|
||||
const noncopyable& operator=( const noncopyable& );
|
||||
}; // noncopyable
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UTILITY_HPP
|
||||
|
443
indirect_iterator.htm
Normal file
443
indirect_iterator.htm
Normal file
@@ -0,0 +1,443 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
||||
<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>Indirect Iterator Adaptor 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>Indirect Iterator Adaptor</h1>
|
||||
Defined in header <a href=
|
||||
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
<p>The indirect iterator adaptor augments an iterator by applying an
|
||||
<b>extra</b> dereference inside of <tt>operator*()</tt>. For example, this
|
||||
iterator makes it possible to view a container of pointers or
|
||||
smart-pointers (e.g. <tt>std::list<boost::shared_ptr<foo>
|
||||
></tt>) as if it were a container of the pointed-to type. The following
|
||||
<b>pseudo-code</b> shows the basic idea of the indirect iterator:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// inside a hypothetical indirect_iterator class...
|
||||
typedef std::iterator_traits<BaseIterator>::value_type Pointer;
|
||||
typedef std::iterator_traits<Pointer>::reference reference;
|
||||
|
||||
reference indirect_iterator::operator*() const {
|
||||
return **this->base_iterator;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class BaseIterator,
|
||||
class Value, class Reference, class Category, class Pointer>
|
||||
struct indirect_iterator_generator;
|
||||
|
||||
template <class BaseIterator,
|
||||
class Value, class Reference, class ConstReference,
|
||||
class Category, class Pointer, class ConstPointer>
|
||||
struct indirect_iterator_pair_generator;
|
||||
|
||||
template <class BaseIterator>
|
||||
typename indirect_iterator_generator<BaseIterator>::type
|
||||
make_indirect_iterator(BaseIterator base)
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<hr>
|
||||
|
||||
<h2><a name="indirect_iterator_generator">The Indirect Iterator Type
|
||||
Generator</a></h2>
|
||||
The <tt>indirect_iterator_generator</tt> template is a <a href=
|
||||
"../../more/generic_programming.html#type_generator">generator</a> of
|
||||
indirect iterator types. The main template parameter for this class is the
|
||||
<tt>BaseIterator</tt> type that is being wrapped. In most cases the type of
|
||||
the elements being pointed to can be deduced using
|
||||
<tt>std::iterator_traits</tt>, but in some situations the user may want to
|
||||
override this type, so there are also template parameters that allow a user
|
||||
to control the <tt>value_type</tt>, <tt>pointer</tt>, and
|
||||
<tt>reference</tt> types of the resulting iterators.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class BaseIterator,
|
||||
class Value, class Reference, class Pointer>
|
||||
class indirect_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href=
|
||||
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting indirect iterator type
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
This example uses the <tt>indirect_iterator_generator</tt> to create
|
||||
indirect iterators which dereference the pointers stored in the
|
||||
<tt>pointers_to_chars</tt> array to access the <tt>char</tt>s in the
|
||||
<tt>characters</tt> array.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <boost/config.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
char characters[] = "abcdefg";
|
||||
const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char
|
||||
char* pointers_to_chars[N]; // at the end.
|
||||
for (int i = 0; i < N; ++i)
|
||||
pointers_to_chars[i] = &characters[i];
|
||||
|
||||
boost::indirect_iterator_generator<char**, char>::type
|
||||
indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N);
|
||||
|
||||
std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<table border>
|
||||
<tr>
|
||||
<th>Parameter
|
||||
|
||||
<th>Description
|
||||
|
||||
<tr>
|
||||
<td><tt>BaseIterator</tt>
|
||||
|
||||
<td>The iterator type being wrapped. The <tt>value_type</tt>
|
||||
of the base iterator should itself be dereferenceable.
|
||||
The return type of the <tt>operator*</tt> for the
|
||||
<tt>value_type</tt> should match the <tt>Reference</tt> type.
|
||||
|
||||
<tr>
|
||||
<td><tt>Value</tt>
|
||||
|
||||
<td>The <tt>value_type</tt> of the resulting iterator, unless const. If
|
||||
Value is <tt>const X</tt>, a conforming compiler makes the
|
||||
<tt>value_type</tt> <tt><i>non-</i>const X</tt><a href=
|
||||
"iterator_adaptors.htm#1">[1]</a>. Note that if the default
|
||||
is used for <tt>Value</tt>, then there must be a valid specialization
|
||||
of <tt>iterator_traits</tt> for the value type of the base iterator.
|
||||
<br>
|
||||
<b>Default:</b> <tt>std::iterator_traits<<br>
|
||||
<20> std::iterator_traits<BaseIterator>::value_type
|
||||
>::value_type</tt><a href="#2">[2]</a>
|
||||
|
||||
<tr>
|
||||
<td><tt>Reference</tt>
|
||||
|
||||
<td>The <tt>reference</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator*()</tt>.<br>
|
||||
<b>Default:</b> <tt>Value&</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>Pointer</tt>
|
||||
|
||||
<td>The <tt>pointer</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator->()</tt>.<br>
|
||||
<b>Default:</b> <tt>Value*</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>Category</tt>
|
||||
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
|
||||
<b>Default:</b>
|
||||
<tt>std::iterator_traits<BaseIterator>::iterator_category</tt>
|
||||
|
||||
</table>
|
||||
|
||||
<h3>Concept Model</h3>
|
||||
The indirect iterator will model whichever <a href=
|
||||
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator
|
||||
concept category</a> is modeled by the base iterator. Thus, if the
|
||||
base iterator is a model of <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so is the resulting indirect iterator. If
|
||||
the base iterator models a more restrictive concept, the resulting
|
||||
indirect iterator will model the same concept <a href="#3">[3]</a>.
|
||||
|
||||
<h3>Members</h3>
|
||||
The indirect iterator type implements the member functions and operators
|
||||
required of the <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
|
||||
Iterator</a> concept. In addition it has the following constructor:
|
||||
<pre>
|
||||
explicit indirect_iterator_generator::type(const BaseIterator& it)
|
||||
</pre>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
|
||||
<h2><a name="indirect_iterator_pair_generator">The Indirect Iterator Pair
|
||||
Generator</a></h2>
|
||||
Sometimes a pair of <tt>const</tt>/non-<tt>const</tt> pair of iterators is
|
||||
needed, such as when implementing a container. The
|
||||
<tt>indirect_iterator_pair_generator</tt> class makes it more convenient to
|
||||
create this pair of iterator types.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class BaseIterator,
|
||||
class Value, class Pointer, class Reference,
|
||||
class ConstPointer, class ConstReference>
|
||||
class indirect_iterator_pair_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href=
|
||||
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> iterator; // the mutable indirect iterator type
|
||||
typedef <tt><a href=
|
||||
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> const_iterator; // the immutable indirect iterator type
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
typedef boost::indirect_iterator_pair_generator<char**,
|
||||
char, char*, char&, const char*, const char&> PairGen;
|
||||
|
||||
char mutable_characters[N];
|
||||
char* pointers_to_mutable_chars[N];
|
||||
for (int i = 0; i < N; ++i)
|
||||
pointers_to_mutable_chars[i] = &mutable_characters[i];
|
||||
|
||||
PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars),
|
||||
mutable_indirect_last(pointers_to_mutable_chars + N);
|
||||
PairGen::const_iterator const_indirect_first(pointers_to_chars),
|
||||
const_indirect_last(pointers_to_chars + N);
|
||||
|
||||
std::transform(const_indirect_first, const_indirect_last,
|
||||
mutable_indirect_first, std::bind1st(std::plus<char>(), 1));
|
||||
|
||||
std::copy(mutable_indirect_first, mutable_indirect_last,
|
||||
std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
// to be continued...
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The output is:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
b,c,d,e,f,g,h,
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<table border>
|
||||
<tr>
|
||||
<th>Parameter
|
||||
|
||||
<th>Description
|
||||
|
||||
<tr>
|
||||
<td><tt>BaseIterator</tt>
|
||||
|
||||
<td>The iterator type being wrapped. The <tt>value_type</tt> of the
|
||||
base iterator should itself be dereferenceable.
|
||||
The return type of the <tt>operator*</tt> for the
|
||||
<tt>value_type</tt> should match the <tt>Reference</tt> type.
|
||||
|
||||
<tr>
|
||||
<td><tt>Value</tt>
|
||||
|
||||
<td>The <tt>value_type</tt> of the resulting iterators.
|
||||
If Value is <tt>const X</tt>, a conforming compiler makes the
|
||||
<tt>value_type</tt> <tt><i>non-</i>const X</tt><a href=
|
||||
"iterator_adaptors.htm#1">[1]</a>. Note that if the default
|
||||
is used for <tt>Value</tt>, then there must be a valid
|
||||
specialization of <tt>iterator_traits</tt> for the value type
|
||||
of the base iterator.<br>
|
||||
|
||||
<b>Default:</b> <tt>std::iterator_traits<<br>
|
||||
<20> std::iterator_traits<BaseIterator>::value_type
|
||||
>::value_type</tt><a href="#2">[2]</a>
|
||||
|
||||
<tr>
|
||||
<td><tt>Reference</tt>
|
||||
|
||||
<td>The <tt>reference</tt> type of the resulting <tt>iterator</tt>, and
|
||||
in particular, the result type of its <tt>operator*()</tt>.<br>
|
||||
<b>Default:</b> <tt>Value&</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>Pointer</tt>
|
||||
|
||||
<td>The <tt>pointer</tt> type of the resulting <tt>iterator</tt>, and
|
||||
in particular, the result type of its <tt>operator->()</tt>.<br>
|
||||
<b>Default:</b> <tt>Value*</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>ConstReference</tt>
|
||||
|
||||
<td>The <tt>reference</tt> type of the resulting
|
||||
<tt>const_iterator</tt>, and in particular, the result type of its
|
||||
<tt>operator*()</tt>.<br>
|
||||
<b>Default:</b> <tt>const Value&</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>ConstPointer</tt>
|
||||
|
||||
<td>The <tt>pointer</tt> type of the resulting <tt>const_iterator</tt>,
|
||||
and in particular, the result type of its <tt>operator->()</tt>.<br>
|
||||
<b>Default:</b> <tt>const Value*</tt>
|
||||
|
||||
<tr>
|
||||
<td><tt>Category</tt>
|
||||
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
|
||||
<b>Default:</b>
|
||||
<tt>std::iterator_traits<BaseIterator>::iterator_category</tt>
|
||||
</table>
|
||||
|
||||
<h3>Concept Model</h3>
|
||||
|
||||
The indirect iterators will model whichever <a href=
|
||||
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator
|
||||
concept category</a> is modeled by the base iterator. Thus, if the
|
||||
base iterator is a model of <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so are the resulting indirect
|
||||
iterators. If the base iterator models a more restrictive concept,
|
||||
the resulting indirect iterators will model the same concept <a
|
||||
href="#3">[3]</a>.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types implement
|
||||
the member functions and operators required of the <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
|
||||
Iterator</a> concept. In addition they support the following constructors:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
explicit indirect_iterator_pair_generator::iterator(const BaseIterator& it)
|
||||
explicit indirect_iterator_pair_generator::const_iterator(const BaseIterator& it)
|
||||
</pre>
|
||||
</blockquote>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
|
||||
<h2><a name="make_indirect_iterator">The Indirect Iterator Object
|
||||
Generator</a></h2>
|
||||
The <tt>make_indirect_iterator()</tt> function provides a more convenient
|
||||
way to create indirect iterator objects. The function saves the user the
|
||||
trouble of explicitly writing out the iterator types.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class BaseIterator>
|
||||
typename indirect_iterator_generator<BaseIterator>::type
|
||||
make_indirect_iterator(BaseIterator base)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
Here we again print the <tt>char</tt>s from the array <tt>characters</tt>
|
||||
by accessing them through the array of pointers <tt>pointer_to_chars</tt>,
|
||||
but this time we use the <tt>make_indirect_iterator()</tt> function which
|
||||
saves us some typing.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
std::copy(boost::make_indirect_iterator(pointers_to_chars),
|
||||
boost::make_indirect_iterator(pointers_to_chars + N),
|
||||
std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
The output is:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
a,b,c,d,e,f,g,
|
||||
</pre>
|
||||
</blockquote>
|
||||
<hr>
|
||||
|
||||
<h3>Notes</h3>
|
||||
|
||||
<p>
|
||||
|
||||
<p><a name="2">[2]</a> If your compiler does not support partial
|
||||
specialization and the base iterator or its <tt>value_type</tt> is a
|
||||
builtin pointer type, you will not be able to use the default for
|
||||
<tt>Value</tt> and will need to specify this type explicitly.
|
||||
|
||||
<p><a name="3">[3]</a>There is a caveat to which concept the
|
||||
indirect iterator can model. If the return type of the
|
||||
<tt>operator*</tt> for the base iterator's value type is not a
|
||||
true reference, then strickly speaking, the indirect iterator can
|
||||
not be a model of <a href=
|
||||
"http://www.sgi.com/tech/stl/ForwardIterator.html">Forward
|
||||
Iterator</a> or any of the concepts that refine it. In this case
|
||||
the <tt>Category</tt> for the indirect iterator should be
|
||||
specified as <tt>std::input_iterator_tag</tt>. However, even in
|
||||
this case, if the base iterator is a random access iterator, the
|
||||
resulting indirect iterator will still satisfy most of the
|
||||
requirements for <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a>.
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
|
||||
|
||||
|
||||
<p>© Copyright Jeremy Siek and David Abrahams 2001. 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.
|
||||
<!-- LocalWords: html charset alt gif hpp BaseIterator const namespace struct
|
||||
-->
|
||||
|
||||
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
|
||||
-->
|
||||
<!-- LocalWords: sizeof PairGen pre Jeremy Siek David Abrahams
|
||||
-->
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
60
indirect_iterator_example.cpp
Normal file
60
indirect_iterator_example.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
char characters[] = "abcdefg";
|
||||
const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char
|
||||
char* pointers_to_chars[N]; // at the end.
|
||||
for (int i = 0; i < N; ++i)
|
||||
pointers_to_chars[i] = &characters[i];
|
||||
|
||||
// Example of using indirect_iterator_generator
|
||||
|
||||
boost::indirect_iterator_generator<char**, char>::type
|
||||
indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N);
|
||||
|
||||
std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Example of using indirect_iterator_pair_generator
|
||||
|
||||
typedef boost::indirect_iterator_pair_generator<char**, char> PairGen;
|
||||
|
||||
char mutable_characters[N];
|
||||
char* pointers_to_mutable_chars[N];
|
||||
for (int i = 0; i < N; ++i)
|
||||
pointers_to_mutable_chars[i] = &mutable_characters[i];
|
||||
|
||||
PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars),
|
||||
mutable_indirect_last(pointers_to_mutable_chars + N);
|
||||
PairGen::const_iterator const_indirect_first(pointers_to_chars),
|
||||
const_indirect_last(pointers_to_chars + N);
|
||||
|
||||
std::transform(const_indirect_first, const_indirect_last,
|
||||
mutable_indirect_first, std::bind1st(std::plus<char>(), 1));
|
||||
|
||||
std::copy(mutable_indirect_first, mutable_indirect_last,
|
||||
std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Example of using make_indirect_iterator()
|
||||
|
||||
std::copy(boost::make_indirect_iterator(pointers_to_chars),
|
||||
boost::make_indirect_iterator(pointers_to_chars + N),
|
||||
std::ostream_iterator<char>(std::cout, ","));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
151
indirect_iterator_test.cpp
Normal file
151
indirect_iterator_test.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// (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.
|
||||
|
||||
// Revision History
|
||||
// 08 Mar 2001 Jeremy Siek
|
||||
// Moved test of indirect iterator into its own file. It to
|
||||
// to be in iterator_adaptor_test.cpp.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <boost/pending/iterator_tests.hpp>
|
||||
#include <boost/concept_archetype.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
|
||||
struct my_iterator_tag : public std::random_access_iterator_tag { };
|
||||
|
||||
using boost::dummyT;
|
||||
|
||||
typedef std::deque<int> storage;
|
||||
typedef std::deque<int*> pointer_deque;
|
||||
typedef std::set<storage::iterator> iterator_set;
|
||||
|
||||
void more_indirect_iterator_tests()
|
||||
{
|
||||
// For some reason all heck breaks loose in the compiler under these conditions.
|
||||
#if !defined(BOOST_MSVC) || !defined(__STL_DEBUG)
|
||||
storage store(1000);
|
||||
std::generate(store.begin(), store.end(), rand);
|
||||
|
||||
pointer_deque ptr_deque;
|
||||
iterator_set iter_set;
|
||||
|
||||
for (storage::iterator p = store.begin(); p != store.end(); ++p)
|
||||
{
|
||||
ptr_deque.push_back(&*p);
|
||||
iter_set.insert(p);
|
||||
}
|
||||
|
||||
typedef boost::indirect_iterator_pair_generator<
|
||||
pointer_deque::iterator
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, int
|
||||
#endif
|
||||
> IndirectDeque;
|
||||
|
||||
IndirectDeque::iterator db(ptr_deque.begin());
|
||||
IndirectDeque::iterator de(ptr_deque.end());
|
||||
assert(static_cast<std::size_t>(de - db) == store.size());
|
||||
assert(db + store.size() == de);
|
||||
IndirectDeque::const_iterator dci(db);
|
||||
assert(db == dci);
|
||||
assert(dci == db);
|
||||
assert(dci != de);
|
||||
assert(dci < de);
|
||||
assert(dci <= de);
|
||||
assert(de >= dci);
|
||||
assert(de > dci);
|
||||
dci = de;
|
||||
assert(dci == de);
|
||||
|
||||
boost::random_access_iterator_test(db + 1, store.size() - 1, boost::next(store.begin()));
|
||||
|
||||
*db = 999;
|
||||
assert(store.front() == 999);
|
||||
|
||||
// Borland C++ is getting very confused about the typedef's here
|
||||
|
||||
typedef boost::indirect_iterator_generator<
|
||||
iterator_set::iterator
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, int
|
||||
#endif
|
||||
>::type indirect_set_iterator;
|
||||
|
||||
typedef boost::indirect_iterator_generator<
|
||||
iterator_set::iterator,
|
||||
const int
|
||||
>::type const_indirect_set_iterator;
|
||||
|
||||
indirect_set_iterator sb(iter_set.begin());
|
||||
indirect_set_iterator se(iter_set.end());
|
||||
const_indirect_set_iterator sci(iter_set.begin());
|
||||
assert(sci == sb);
|
||||
assert(sci != se);
|
||||
sci = se;
|
||||
assert(sci == se);
|
||||
|
||||
*boost::prior(se) = 888;
|
||||
assert(store.back() == 888);
|
||||
assert(std::equal(sb, se, store.begin()));
|
||||
|
||||
boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]);
|
||||
assert(std::equal(db, de, store.begin()));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
|
||||
dummyT(3), dummyT(4), dummyT(5) };
|
||||
const int N = sizeof(array)/sizeof(dummyT);
|
||||
|
||||
// Test indirect_iterator_generator
|
||||
{
|
||||
dummyT* ptr[N];
|
||||
for (int k = 0; k < N; ++k)
|
||||
ptr[k] = array + k;
|
||||
|
||||
typedef boost::indirect_iterator_generator<dummyT**
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, dummyT
|
||||
#endif
|
||||
>::type indirect_iterator;
|
||||
|
||||
typedef boost::indirect_iterator_generator<dummyT**, const dummyT>::type const_indirect_iterator;
|
||||
|
||||
indirect_iterator i(ptr);
|
||||
boost::random_access_iterator_test(i, N, array);
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);
|
||||
#endif
|
||||
|
||||
// check operator->
|
||||
assert((*i).m_x == i->foo());
|
||||
|
||||
const_indirect_iterator j(ptr);
|
||||
boost::random_access_iterator_test(j, N, array);
|
||||
|
||||
dummyT*const* const_ptr = ptr;
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array);
|
||||
#endif
|
||||
boost::const_nonconst_iterator_test(i, ++j);
|
||||
|
||||
more_indirect_iterator_tests();
|
||||
}
|
||||
std::cout << "test successful " << std::endl;
|
||||
return 0;
|
||||
}
|
27
iter_adaptor_fail_expected1.cpp
Normal file
27
iter_adaptor_fail_expected1.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Test boost/pending/iterator_adaptors.hpp
|
||||
|
||||
// (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
|
||||
// 21 Jan 01 Initial version (Jeremy Siek)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <list>
|
||||
#include <boost/pending/iterator_adaptors.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef boost::iterator_adaptor<std::list<int>::iterator,
|
||||
boost::default_iterator_policies,
|
||||
int,int&,int*,std::bidirectional_iterator_tag> adaptor_type;
|
||||
|
||||
adaptor_type i;
|
||||
i += 4;
|
||||
return 0;
|
||||
}
|
28
iter_adaptor_fail_expected2.cpp
Normal file
28
iter_adaptor_fail_expected2.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Test boost/pending/iterator_adaptors.hpp
|
||||
|
||||
// (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
|
||||
// 21 Jan 01 Initial version (Jeremy Siek)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <boost/pending/iterator_adaptors.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef boost::iterator_adaptor<std::istream_iterator<int>,
|
||||
boost::default_iterator_policies,
|
||||
int,int&,int*,std::input_iterator_tag> adaptor_type;
|
||||
|
||||
adaptor_type iter;
|
||||
--iter;
|
||||
return 0;
|
||||
}
|
61
iter_traits_gen_test.cpp
Normal file
61
iter_traits_gen_test.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.
|
||||
|
||||
// 8 Mar 2001 Jeremy Siek
|
||||
// Initial checkin.
|
||||
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <boost/pending/iterator_tests.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
class bar { };
|
||||
void foo(bar) { }
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using boost::dummyT;
|
||||
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
|
||||
dummyT(3), dummyT(4), dummyT(5) };
|
||||
typedef boost::iterator_adaptor<dummyT*,
|
||||
boost::default_iterator_policies, dummyT> my_iter;
|
||||
my_iter mi(array);
|
||||
|
||||
{
|
||||
typedef boost::iterator_adaptor<my_iter, boost::default_iterator_policies,
|
||||
boost::iterator_traits_generator
|
||||
::reference<dummyT>
|
||||
::iterator_category<std::input_iterator_tag> > iter_type;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<iter_type::iterator_category*,
|
||||
std::input_iterator_tag*>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT(( ! boost::is_convertible<iter_type::iterator_category*,
|
||||
std::forward_iterator_tag*>::value));
|
||||
|
||||
iter_type i(mi);
|
||||
boost::input_iterator_test(i, dummyT(0), dummyT(1));
|
||||
}
|
||||
{
|
||||
typedef boost::iterator_adaptor<dummyT*,
|
||||
boost::default_iterator_policies,
|
||||
boost::iterator_traits_generator
|
||||
::value_type<dummyT>
|
||||
::reference<const dummyT&>
|
||||
::pointer<const dummyT*>
|
||||
::iterator_category<std::forward_iterator_tag>
|
||||
::difference_type<std::ptrdiff_t> > adaptor_type;
|
||||
|
||||
adaptor_type i(array);
|
||||
|
||||
boost::input_iterator_test(i, dummyT(0), dummyT(1));
|
||||
int zero = 0;
|
||||
if (zero) // don't do this, just make sure it compiles
|
||||
assert((*i).m_x == i->foo());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -7,7 +7,8 @@
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <boost/pending/iterator_adaptors.hpp>
|
||||
#include <boost/pending/integer_range.hpp>
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
@@ -15,6 +16,7 @@ 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 };
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Demonstrate and test boost/operators.hpp on std::iterators -------------//
|
||||
// Test boost/iterator_adaptors.hpp
|
||||
|
||||
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
@@ -9,40 +9,58 @@
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 08 Mar 01 Moved indirect and transform tests to separate files.
|
||||
// (Jeremy Siek)
|
||||
// 19 Feb 01 Take adavantage of improved iterator_traits to do more tests
|
||||
// on MSVC. Hack around an MSVC-with-STLport internal compiler
|
||||
// error. (David Abrahams)
|
||||
// 11 Feb 01 Added test of operator-> for forward and input iterators.
|
||||
// (Jeremy Siek)
|
||||
// 11 Feb 01 Borland fixes (David Abrahams)
|
||||
// 10 Feb 01 Use new adaptors interface. (David Abrahams)
|
||||
// 10 Feb 01 Use new filter_ interface. (David Abrahams)
|
||||
// 09 Feb 01 Use new reverse_ and indirect_ interfaces. Replace
|
||||
// BOOST_NO_STD_ITERATOR_TRAITS with
|
||||
// BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've
|
||||
// normalized to core compiler capabilities (David Abrahams)
|
||||
// 08 Feb 01 Use Jeremy's new make_reverse_iterator form; add more
|
||||
// comprehensive testing. Force-decay array function arguments to
|
||||
// pointers.
|
||||
// 07 Feb 01 Added tests for the make_xxx_iterator() helper functions.
|
||||
// (Jeremy Siek)
|
||||
// 07 Feb 01 Replaced use of xxx_pair_generator with xxx_generator where
|
||||
// possible (which was all but the projection iterator).
|
||||
// (Jeremy Siek)
|
||||
// 06 Feb 01 Removed now-defaulted template arguments where possible
|
||||
// Updated names to correspond to new generator naming convention.
|
||||
// Added a trivial test for make_transform_iterator().
|
||||
// Gave traits for const iterators a mutable value_type, per std.
|
||||
// Resurrected my original tests for indirect iterators.
|
||||
// (David Abrahams)
|
||||
// 04 Feb 01 Fix for compilers without standard iterator_traits
|
||||
// (David Abrahams)
|
||||
// 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/iterator_adaptors.hpp>
|
||||
#include <boost/iterator_tests.hpp>
|
||||
#include <boost/pending/iterator_tests.hpp>
|
||||
#include <boost/pending/integer_range.hpp>
|
||||
#include <boost/concept_archetype.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
|
||||
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;
|
||||
@@ -57,79 +75,153 @@ struct mult_functor {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
struct one_or_four {
|
||||
bool operator()(dummyT x) const {
|
||||
return x.foo() == 1 || x.foo() == 4;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::deque<int> storage;
|
||||
typedef std::deque<int*> pointer_deque;
|
||||
typedef std::set<storage::iterator> iterator_set;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
|
||||
dummyT(3), dummyT(4), dummyT(5) };
|
||||
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
|
||||
// Check that the policy concept checks and the default policy
|
||||
// implementation match up.
|
||||
boost::function_requires<
|
||||
boost::RandomAccessIteratorPoliciesConcept<
|
||||
boost::default_iterator_policies, int*,
|
||||
boost::iterator<std::random_access_iterator_tag, int, std::ptrdiff_t,
|
||||
int*, int&>
|
||||
> >();
|
||||
|
||||
// Test the iterator_adaptor
|
||||
{
|
||||
My::iterator i = array;
|
||||
boost::iterator_adaptor<dummyT*, boost::default_iterator_policies, dummyT> i(array);
|
||||
boost::random_access_iterator_test(i, N, array);
|
||||
|
||||
My::const_iterator j = array;
|
||||
boost::iterator_adaptor<const dummyT*, boost::default_iterator_policies, const dummyT> 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_iterator
|
||||
{
|
||||
dummyT* ptr[N];
|
||||
// Test projection_iterator_pair_generator
|
||||
{
|
||||
typedef std::pair<dummyT,dummyT> Pair;
|
||||
Pair pair_array[N];
|
||||
for (int k = 0; k < N; ++k)
|
||||
ptr[k] = array + k;
|
||||
pair_array[k].first = array[k];
|
||||
|
||||
typedef boost::projection_iterator_pair_generator<select1st_<Pair>,
|
||||
Pair*, const Pair*
|
||||
> Projection;
|
||||
|
||||
typedef dummyT* DummyPtr;
|
||||
typedef boost::indirect_iterators<DummyPtr*, const DummyPtr*,
|
||||
boost::iterator<std::random_access_iterator_tag, DummyPtr>,
|
||||
boost::iterator<std::random_access_iterator_tag, const DummyPtr>,
|
||||
boost::iterator<std::random_access_iterator_tag, dummyT>
|
||||
> Indirect;
|
||||
Indirect::iterator i = ptr;
|
||||
Projection::iterator i(pair_array);
|
||||
boost::random_access_iterator_test(i, N, array);
|
||||
|
||||
Indirect::const_iterator j = ptr;
|
||||
boost::random_access_iterator_test(boost::make_projection_iterator(pair_array, select1st_<Pair>()), N, array);
|
||||
boost::random_access_iterator_test(boost::make_projection_iterator< select1st_<Pair> >(pair_array), N, array);
|
||||
|
||||
Projection::const_iterator j(pair_array);
|
||||
boost::random_access_iterator_test(j, N, array);
|
||||
|
||||
boost::const_nonconst_iterator_test(i, ++j);
|
||||
boost::random_access_iterator_test(boost::make_const_projection_iterator(pair_array, select1st_<Pair>()), N, array);
|
||||
boost::random_access_iterator_test(boost::make_const_projection_iterator<select1st_<Pair> >(pair_array), N, array);
|
||||
|
||||
boost::const_nonconst_iterator_test(i, ++j);
|
||||
}
|
||||
// Test reverse_iterators
|
||||
|
||||
// Test reverse_iterator_generator
|
||||
{
|
||||
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;
|
||||
typedef boost::reverse_iterator_generator<dummyT*
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, dummyT
|
||||
#endif
|
||||
>::type reverse_iterator;
|
||||
|
||||
reverse_iterator i(reversed + N);
|
||||
boost::random_access_iterator_test(i, N, array);
|
||||
|
||||
Reverse::const_iterator j = reversed + N;
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
|
||||
#endif
|
||||
|
||||
typedef boost::reverse_iterator_generator<const dummyT*
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, const dummyT
|
||||
#endif
|
||||
>::type const_reverse_iterator;
|
||||
|
||||
const_reverse_iterator j(reversed + N);
|
||||
boost::random_access_iterator_test(j, N, array);
|
||||
|
||||
const dummyT* const_reversed = reversed;
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
|
||||
#endif
|
||||
|
||||
boost::const_nonconst_iterator_test(i, ++j);
|
||||
}
|
||||
|
||||
// Test reverse_iterator_generator again, with traits fully deducible on all platforms
|
||||
{
|
||||
std::deque<dummyT> reversed_container;
|
||||
std::reverse_copy(array, array + N, std::back_inserter(reversed_container));
|
||||
const std::deque<dummyT>::iterator reversed = reversed_container.begin();
|
||||
|
||||
|
||||
typedef boost::reverse_iterator_generator<
|
||||
std::deque<dummyT>::iterator>::type reverse_iterator;
|
||||
typedef boost::reverse_iterator_generator<
|
||||
std::deque<dummyT>::const_iterator, const dummyT>::type const_reverse_iterator;
|
||||
|
||||
// MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation
|
||||
// (e.g. "reversed + N") is used in the constructor below.
|
||||
const std::deque<dummyT>::iterator finish = reversed_container.end();
|
||||
reverse_iterator i(finish);
|
||||
|
||||
boost::random_access_iterator_test(i, N, array);
|
||||
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
|
||||
|
||||
const_reverse_iterator j = reverse_iterator(finish);
|
||||
boost::random_access_iterator_test(j, N, array);
|
||||
|
||||
const std::deque<dummyT>::const_iterator const_reversed = reversed;
|
||||
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
|
||||
|
||||
// Many compilers' builtin deque iterators don't interoperate well, though
|
||||
// STLport fixes that problem.
|
||||
#if defined(__SGI_STL_PORT) || !defined(__GNUC__) && !defined(__BORLANDC__) && !defined(BOOST_MSVC)
|
||||
boost::const_nonconst_iterator_test(i, ++j);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test integer_range's iterators
|
||||
{
|
||||
int int_array[] = { 0, 1, 2, 3, 4, 5 };
|
||||
@@ -137,7 +229,107 @@ main()
|
||||
boost::random_access_iterator_test(r.begin(), r.size(), int_array);
|
||||
}
|
||||
|
||||
std::cout << "test successful " << std::endl;
|
||||
// Test filter iterator
|
||||
{
|
||||
// Using typedefs for filter_gen::type confused Borland terribly.
|
||||
typedef boost::detail::non_bidirectional_category<dummyT*>::type category;
|
||||
|
||||
typedef boost::filter_iterator_generator<one_or_four, dummyT*
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, dummyT
|
||||
#endif
|
||||
>::type filter_iter;
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
// Borland is choking on accessing the policies_type explicitly
|
||||
// from the filter_iter.
|
||||
boost::forward_iterator_test(make_filter_iterator(array, array+N,
|
||||
one_or_four()),
|
||||
dummyT(1), dummyT(4));
|
||||
#else
|
||||
filter_iter i(array, filter_iter::policies_type(one_or_four(), array + N));
|
||||
boost::forward_iterator_test(i, dummyT(1), dummyT(4));
|
||||
#endif
|
||||
|
||||
#if !defined(__BORLANDC__)
|
||||
//
|
||||
enum { is_forward = boost::is_same<
|
||||
filter_iter::iterator_category,
|
||||
std::forward_iterator_tag>::value };
|
||||
BOOST_STATIC_ASSERT(is_forward);
|
||||
#endif
|
||||
|
||||
// On compilers not supporting partial specialization, we can do more type
|
||||
// deduction with deque iterators than with pointers... unless the library
|
||||
// is broken ;-(
|
||||
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
|
||||
std::deque<dummyT> array2;
|
||||
std::copy(array+0, array+N, std::back_inserter(array2));
|
||||
boost::forward_iterator_test(
|
||||
boost::make_filter_iterator(array2.begin(), array2.end(), one_or_four()),
|
||||
dummyT(1), dummyT(4));
|
||||
|
||||
boost::forward_iterator_test(
|
||||
boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()),
|
||||
dummyT(1), dummyT(4));
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_MSVC) // This just freaks MSVC out completely
|
||||
boost::forward_iterator_test(
|
||||
boost::make_filter_iterator<one_or_four>(
|
||||
boost::make_reverse_iterator(array2.end()),
|
||||
boost::make_reverse_iterator(array2.begin())
|
||||
),
|
||||
dummyT(4), dummyT(1));
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
boost::forward_iterator_test(
|
||||
boost::make_filter_iterator(array+0, array+N, one_or_four()),
|
||||
dummyT(1), dummyT(4));
|
||||
|
||||
boost::forward_iterator_test(
|
||||
boost::make_filter_iterator<one_or_four>(array, array + N),
|
||||
dummyT(1), dummyT(4));
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// check operator-> with a forward iterator
|
||||
{
|
||||
boost::forward_iterator_archetype<dummyT> forward_iter;
|
||||
#if defined(__BORLANDC__)
|
||||
typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
|
||||
boost::default_iterator_policies,
|
||||
dummyT, const dummyT&, const dummyT*,
|
||||
std::forward_iterator_tag, std::ptrdiff_t> adaptor_type;
|
||||
#else
|
||||
typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
|
||||
boost::default_iterator_policies,
|
||||
boost::iterator_traits_generator
|
||||
::value_type<dummyT>
|
||||
::reference<const dummyT&>
|
||||
::pointer<const dummyT*>
|
||||
::iterator_category<std::forward_iterator_tag>
|
||||
::difference_type<std::ptrdiff_t> > adaptor_type;
|
||||
#endif
|
||||
adaptor_type i(forward_iter);
|
||||
int zero = 0;
|
||||
if (zero) // don't do this, just make sure it compiles
|
||||
assert((*i).m_x == i->foo());
|
||||
}
|
||||
// check operator-> with an input iterator
|
||||
{
|
||||
boost::input_iterator_archetype<dummyT> input_iter;
|
||||
typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>,
|
||||
boost::default_iterator_policies,
|
||||
dummyT, const dummyT&, const dummyT*,
|
||||
std::input_iterator_tag, std::ptrdiff_t> adaptor_type;
|
||||
adaptor_type i(input_iter);
|
||||
int zero = 0;
|
||||
if (zero) // don't do this, just make sure it compiles
|
||||
assert((*i).m_x == i->foo());
|
||||
}
|
||||
std::cout << "test successful " << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
210
iterator_traits_test.cpp
Normal file
210
iterator_traits_test.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
// (C) Copyright David Abrahams 2001. 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
|
||||
// 04 Mar 2001 Patches for Intel C++ (Dave Abrahams)
|
||||
// 19 Feb 2001 Take advantage of improved iterator_traits to do more tests
|
||||
// on MSVC. Reordered some #ifdefs for coherency.
|
||||
// (David Abrahams)
|
||||
// 13 Feb 2001 Test new VC6 workarounds (David Abrahams)
|
||||
// 11 Feb 2001 Final fixes for Borland (David Abrahams)
|
||||
// 11 Feb 2001 Some fixes for Borland get it closer on that compiler
|
||||
// (David Abrahams)
|
||||
// 07 Feb 2001 More comprehensive testing; factored out static tests for
|
||||
// better reuse (David Abrahams)
|
||||
// 21 Jan 2001 Quick fix to my_iterator, which wasn't returning a
|
||||
// reference type from operator* (David Abrahams)
|
||||
// 19 Jan 2001 Initial version with iterator operators (David Abrahams)
|
||||
|
||||
#include <boost/detail/iterator.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// An iterator for which we can get traits.
|
||||
struct my_iterator1
|
||||
: boost::forward_iterator_helper<my_iterator1, char, long, const char*, const char&>
|
||||
{
|
||||
my_iterator1(const char* p) : m_p(p) {}
|
||||
|
||||
bool operator==(const my_iterator1& rhs) const
|
||||
{ return this->m_p == rhs.m_p; }
|
||||
|
||||
my_iterator1& operator++() { ++this->m_p; return *this; }
|
||||
const char& operator*() { return *m_p; }
|
||||
private:
|
||||
const char* m_p;
|
||||
};
|
||||
|
||||
// Used to prove that we don't require std::iterator<> in the hierarchy under
|
||||
// MSVC6, and that we can compute all the traits for a standard-conforming UDT
|
||||
// iterator.
|
||||
struct my_iterator2
|
||||
: boost::equality_comparable<my_iterator2
|
||||
, boost::incrementable<my_iterator2
|
||||
, boost::dereferenceable<my_iterator2,const char*> > >
|
||||
{
|
||||
typedef char value_type;
|
||||
typedef long difference_type;
|
||||
typedef const char* pointer;
|
||||
typedef const char& reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
my_iterator2(const char* p) : m_p(p) {}
|
||||
|
||||
bool operator==(const my_iterator2& rhs) const
|
||||
{ return this->m_p == rhs.m_p; }
|
||||
|
||||
my_iterator2& operator++() { ++this->m_p; return *this; }
|
||||
const char& operator*() { return *m_p; }
|
||||
private:
|
||||
const char* m_p;
|
||||
};
|
||||
|
||||
// Used to prove that we're not overly confused by the existence of
|
||||
// std::iterator<> in the hierarchy under MSVC6 - we should find that
|
||||
// boost::detail::iterator_traits<my_iterator3>::difference_type is int.
|
||||
struct my_iterator3 : my_iterator1
|
||||
{
|
||||
typedef int difference_type;
|
||||
my_iterator3(const char* p) : my_iterator1(p) {}
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct non_portable_tests
|
||||
{
|
||||
// Unfortunately, the VC6 standard library doesn't supply these :(
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::pointer,
|
||||
pointer
|
||||
>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::reference,
|
||||
reference
|
||||
>::value));
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct portable_tests
|
||||
{
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::difference_type,
|
||||
difference_type
|
||||
>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::iterator_category,
|
||||
category
|
||||
>::value));
|
||||
};
|
||||
|
||||
// Test iterator_traits
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct input_iterator_test
|
||||
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
{
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::value_type,
|
||||
value_type
|
||||
>::value));
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct non_pointer_test
|
||||
: input_iterator_test<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct maybe_pointer_test
|
||||
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
input_iterator_test<std::istream_iterator<int>, int, std::ptrdiff_t, int*, int&, std::input_iterator_tag>
|
||||
istream_iterator_test;
|
||||
|
||||
//
|
||||
#if defined(__BORLANDC__) && !defined(__SGI_STL_PORT)
|
||||
typedef ::std::char_traits<char>::off_type distance;
|
||||
non_pointer_test<std::ostream_iterator<int>,int,
|
||||
distance,int*,int&,std::output_iterator_tag> ostream_iterator_test;
|
||||
#elif defined(BOOST_MSVC_STD_ITERATOR)
|
||||
non_pointer_test<std::ostream_iterator<int>,
|
||||
int, void, void, void, std::output_iterator_tag>
|
||||
ostream_iterator_test;
|
||||
#else
|
||||
non_pointer_test<std::ostream_iterator<int>,
|
||||
void, void, void, void, std::output_iterator_tag>
|
||||
ostream_iterator_test;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __KCC
|
||||
typedef long std_list_diff_type;
|
||||
#else
|
||||
typedef std::ptrdiff_t std_list_diff_type;
|
||||
#endif
|
||||
non_pointer_test<std::list<int>::iterator, int, std_list_diff_type, int*, int&, std::bidirectional_iterator_tag>
|
||||
list_iterator_test;
|
||||
|
||||
maybe_pointer_test<std::vector<int>::iterator, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
|
||||
vector_iterator_test;
|
||||
|
||||
maybe_pointer_test<int*, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
|
||||
int_pointer_test;
|
||||
|
||||
non_pointer_test<my_iterator1, char, long, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator1_test;
|
||||
|
||||
non_pointer_test<my_iterator2, char, long, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator2_test;
|
||||
|
||||
non_pointer_test<my_iterator3, char, int, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator3_test;
|
||||
|
||||
int main()
|
||||
{
|
||||
char chars[100];
|
||||
int ints[100];
|
||||
|
||||
for (std::ptrdiff_t length = 3; length < 100; length += length / 3)
|
||||
{
|
||||
std::list<int> l(length);
|
||||
assert(boost::detail::distance(l.begin(), l.end()) == length);
|
||||
|
||||
std::vector<int> v(length);
|
||||
assert(boost::detail::distance(v.begin(), v.end()) == length);
|
||||
|
||||
assert(boost::detail::distance(&ints[0], ints + length) == length);
|
||||
assert(boost::detail::distance(my_iterator1(chars), my_iterator1(chars + length)) == length);
|
||||
assert(boost::detail::distance(my_iterator2(chars), my_iterator2(chars + length)) == length);
|
||||
assert(boost::detail::distance(my_iterator3(chars), my_iterator3(chars + length)) == length);
|
||||
}
|
||||
return 0;
|
||||
}
|
393
numeric_traits_test.cpp
Normal file
393
numeric_traits_test.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
// (C) Copyright David Abrahams 2001. 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
|
||||
// 11 Feb 2001 Fixes for Borland (David Abrahams)
|
||||
// 23 Jan 2001 Added test for wchar_t (David Abrahams)
|
||||
// 23 Jan 2001 Now statically selecting a test for signed numbers to avoid
|
||||
// warnings with fancy compilers. Added commentary and
|
||||
// additional dumping of traits data for tested types (David
|
||||
// Abrahams).
|
||||
// 21 Jan 2001 Initial version (David Abrahams)
|
||||
|
||||
#include <boost/detail/numeric_traits.hpp>
|
||||
#include <cassert>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <climits>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
# include <limits>
|
||||
#endif
|
||||
|
||||
// A macro for declaring class compile-time constants.
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
# define DECLARE_CLASS_CONST(type, init) static const type init
|
||||
#else
|
||||
# define DECLARE_CLASS_CONST(type, init) enum { init }
|
||||
#endif
|
||||
|
||||
// =================================================================================
|
||||
// template class complement_traits<Number> --
|
||||
//
|
||||
// statically computes the max and min for 1s and 2s-complement binary
|
||||
// numbers. This helps on platforms without <limits> support. It also shows
|
||||
// an example of a recursive template that works with MSVC!
|
||||
//
|
||||
|
||||
template <unsigned size> struct complement; // forward
|
||||
|
||||
// The template complement, below, does all the real work, using "poor man's
|
||||
// partial specialization". We need complement_traits_aux<> so that MSVC doesn't
|
||||
// complain about undefined min/max as we're trying to recursively define them.
|
||||
template <class Number, unsigned size>
|
||||
struct complement_traits_aux
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = complement<size>::template traits<Number>::max);
|
||||
DECLARE_CLASS_CONST(Number, min = complement<size>::template traits<Number>::min);
|
||||
};
|
||||
|
||||
template <unsigned size>
|
||||
struct complement
|
||||
{
|
||||
template <class Number>
|
||||
struct traits
|
||||
{
|
||||
private:
|
||||
// indirection through complement_traits_aux neccessary to keep MSVC happy
|
||||
typedef complement_traits_aux<Number, size - 1> prev;
|
||||
public:
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
Number(Number(prev::max) << CHAR_BIT)
|
||||
+ Number(UCHAR_MAX));
|
||||
|
||||
DECLARE_CLASS_CONST(Number, min = Number(Number(prev::min) << CHAR_BIT));
|
||||
};
|
||||
};
|
||||
|
||||
// Template class complement_base<> -- defines values for min and max for
|
||||
// complement<1>, at the deepest level of recursion. Uses "poor man's partial
|
||||
// specialization" again.
|
||||
template <bool is_signed> struct complement_base;
|
||||
|
||||
template <> struct complement_base<false>
|
||||
{
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = 0);
|
||||
DECLARE_CLASS_CONST(Number, max = UCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct complement_base<true>
|
||||
{
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = SCHAR_MIN);
|
||||
DECLARE_CLASS_CONST(Number, max = SCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
// Base specialization of complement, puts an end to the recursion.
|
||||
template <>
|
||||
struct complement<1>
|
||||
{
|
||||
template <class Number>
|
||||
struct traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(bool, is_signed = boost::detail::is_signed<Number>::value);
|
||||
DECLARE_CLASS_CONST(Number, min =
|
||||
complement_base<is_signed>::template values<Number>::min);
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
complement_base<is_signed>::template values<Number>::max);
|
||||
};
|
||||
};
|
||||
|
||||
// Now here's the "pretty" template you're intended to actually use.
|
||||
// complement_traits<Number>::min, complement_traits<Number>::max are the
|
||||
// minimum and maximum values of Number if Number is a built-in integer type.
|
||||
template <class Number>
|
||||
struct complement_traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
|
||||
DECLARE_CLASS_CONST(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
|
||||
};
|
||||
|
||||
// =================================================================================
|
||||
|
||||
// Support for streaming various numeric types in exactly the format I want. I
|
||||
// needed this in addition to all the assertions so that I could see exactly
|
||||
// what was going on.
|
||||
//
|
||||
// Numbers go through a 2-stage conversion process (by default, though, no real
|
||||
// conversion).
|
||||
//
|
||||
template <class T> struct stream_as {
|
||||
typedef T t1;
|
||||
typedef T t2;
|
||||
};
|
||||
|
||||
// char types first get converted to unsigned char, then to unsigned.
|
||||
template <> struct stream_as<char> {
|
||||
typedef unsigned char t1;
|
||||
typedef unsigned t2;
|
||||
};
|
||||
template <> struct stream_as<unsigned char> {
|
||||
typedef unsigned char t1; typedef unsigned t2;
|
||||
};
|
||||
template <> struct stream_as<signed char> {
|
||||
typedef unsigned char t1; typedef unsigned t2;
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
|
||||
// On this platform, __int64 and __uint64 get streamed as strings
|
||||
template <> struct stream_as<boost::uintmax_t> {
|
||||
typedef std::string t1;
|
||||
typedef std::string t2;
|
||||
};
|
||||
|
||||
template <> struct stream_as<boost::intmax_t> {
|
||||
typedef std::string t1;
|
||||
typedef std::string t2;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Standard promotion process for streaming
|
||||
template <class T> struct promote
|
||||
{
|
||||
static typename stream_as<T>::t1 from(T x) {
|
||||
typedef typename stream_as<T>::t1 t1;
|
||||
return t1(x);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
|
||||
// On this platform, stream them as long/unsigned long if they fit.
|
||||
// Otherwise, write a string.
|
||||
template <> struct promote<boost::uintmax_t> {
|
||||
std::string static from(const boost::uintmax_t x) {
|
||||
if (x > ULONG_MAX)
|
||||
return std::string("large unsigned value");
|
||||
else
|
||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
||||
}
|
||||
};
|
||||
template <> struct promote<boost::intmax_t> {
|
||||
std::string static from(const boost::intmax_t x) {
|
||||
if (x > boost::intmax_t(ULONG_MAX))
|
||||
return std::string("large positive signed value");
|
||||
else if (x >= 0)
|
||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
||||
|
||||
if (x < boost::intmax_t(LONG_MIN))
|
||||
return std::string("large negative signed value");
|
||||
else
|
||||
return boost::lexical_cast<std::string>((long)x);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// This is the function which converts types to the form I want to stream them in.
|
||||
template <class T>
|
||||
typename stream_as<T>::t2 stream_number(T x)
|
||||
{
|
||||
return promote<T>::from(x);
|
||||
}
|
||||
// =================================================================================
|
||||
|
||||
//
|
||||
// Tests for built-in signed and unsigned types
|
||||
//
|
||||
|
||||
// Tag types for selecting tests
|
||||
struct unsigned_tag {};
|
||||
struct signed_tag {};
|
||||
|
||||
// Tests for unsigned numbers. The extra default Number parameter works around
|
||||
// an MSVC bug.
|
||||
template <class Number>
|
||||
void test_aux(unsigned_tag, Number* = 0)
|
||||
{
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||
| (boost::is_same<difference_type, boost::intmax_t>::value));
|
||||
|
||||
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) == Number(0));
|
||||
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
|
||||
? max
|
||||
: max / 2 - 1;
|
||||
|
||||
std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = "
|
||||
<< stream_number(max) << "..." << std::flush;
|
||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||
<< std::flush;
|
||||
|
||||
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
|
||||
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
|
||||
|
||||
std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
|
||||
<< std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
|
||||
assert(d1 == difference_type(test_max));
|
||||
assert(d2 == -difference_type(test_max));
|
||||
}
|
||||
|
||||
// Tests for signed numbers. The extra default Number parameter works around an
|
||||
// MSVC bug.
|
||||
struct out_of_range_tag {};
|
||||
struct in_range_tag {};
|
||||
|
||||
// This test morsel gets executed for numbers whose difference will always be
|
||||
// representable in intmax_t
|
||||
template <class Number>
|
||||
void signed_test(in_range_tag, Number* = 0)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
difference_type d1 = boost::detail::numeric_distance(min, max);
|
||||
difference_type d2 = boost::detail::numeric_distance(max, min);
|
||||
|
||||
std::cout << stream_number(min) << "->" << stream_number(max) << "==";
|
||||
std::cout << std::dec << stream_number(d1) << "; ";
|
||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(min)
|
||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
assert(d1 == difference_type(max) - difference_type(min));
|
||||
assert(d2 == difference_type(min) - difference_type(max));
|
||||
}
|
||||
|
||||
// This test morsel gets executed for numbers whose difference may exceed the
|
||||
// capacity of intmax_t.
|
||||
template <class Number>
|
||||
void signed_test(out_of_range_tag, Number* = 0)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
difference_type min_distance = complement_traits<difference_type>::min;
|
||||
difference_type max_distance = complement_traits<difference_type>::max;
|
||||
|
||||
const Number n1 = Number(min + max_distance);
|
||||
const Number n2 = Number(max + min_distance);
|
||||
difference_type d1 = boost::detail::numeric_distance(min, n1);
|
||||
difference_type d2 = boost::detail::numeric_distance(max, n2);
|
||||
|
||||
std::cout << stream_number(min) << "->" << stream_number(n1) << "==";
|
||||
std::cout << std::dec << stream_number(d1) << "; ";
|
||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(n2)
|
||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
assert(d1 == max_distance);
|
||||
assert(d2 == min_distance);
|
||||
}
|
||||
|
||||
template <class Number>
|
||||
void test_aux(signed_tag, Number* = 0)
|
||||
{
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||
| (boost::is_same<difference_type, Number>::value));
|
||||
|
||||
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
|
||||
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
|
||||
<< stream_number(max) << "..." << std::flush;
|
||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||
<< std::flush;
|
||||
|
||||
typedef typename boost::detail::if_true<
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))>
|
||||
::template then<
|
||||
in_range_tag,
|
||||
out_of_range_tag
|
||||
>::type
|
||||
range_tag;
|
||||
signed_test<Number>(range_tag());
|
||||
}
|
||||
|
||||
|
||||
// Test for all numbers. The extra default Number parameter works around an MSVC
|
||||
// bug.
|
||||
template <class Number>
|
||||
void test(Number* = 0)
|
||||
{
|
||||
std::cout << "testing " << typeid(Number).name() << ":\n"
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
<< "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n")
|
||||
<< "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n")
|
||||
<< "digits: " << std::numeric_limits<Number>::digits << "\n"
|
||||
#endif
|
||||
<< "..." << std::flush;
|
||||
|
||||
// factoring out difference_type for the assert below confused Borland :(
|
||||
typedef boost::detail::is_signed<
|
||||
#ifndef BOOST_MSVC
|
||||
typename
|
||||
#endif
|
||||
boost::detail::numeric_traits<Number>::difference_type
|
||||
> is_signed;
|
||||
BOOST_STATIC_ASSERT(is_signed::value);
|
||||
|
||||
typedef typename boost::detail::if_true<
|
||||
boost::detail::is_signed<Number>::value
|
||||
>::template then<signed_tag, unsigned_tag>::type signedness;
|
||||
|
||||
test_aux<Number>(signedness());
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<char>();
|
||||
test<unsigned char>();
|
||||
test<signed char>();
|
||||
test<wchar_t>();
|
||||
test<short>();
|
||||
test<unsigned short>();
|
||||
test<int>();
|
||||
test<unsigned int>();
|
||||
test<long>();
|
||||
test<unsigned long>();
|
||||
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
|
||||
test<long long>();
|
||||
test<unsigned long long>();
|
||||
#elif defined(BOOST_MSVC)
|
||||
// The problem of not having compile-time static class constants other than
|
||||
// enums prevents this from working, since values get truncated.
|
||||
// test<boost::uintmax_t>();
|
||||
// test<boost::intmax_t>();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
597
operators.htm
Normal file
597
operators.htm
Normal file
@@ -0,0 +1,597 @@
|
||||
<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/operators.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/operators.hpp">boost/operators.hpp</a></h1>
|
||||
<p>Header <a href="../../boost/operators.hpp">boost/operators.hpp</a> supplies
|
||||
(in namespace boost) several sets of templates:</p>
|
||||
<ul>
|
||||
<li><a href="#Arithmetic">Arithmetic operators</a>.
|
||||
<li><a href="#deref and helpers">Dereference operators and iterator helpers.</a></li>
|
||||
</ul>
|
||||
<p>These templates define many global operators in terms of a minimal number of
|
||||
fundamental operators.</p>
|
||||
<h1><a name="Arithmetic">Arithmetic</a> Operators</h1>
|
||||
<p>If, for example, you declare a class like this:</p>
|
||||
<blockquote>
|
||||
<pre>class MyInt : boost::operators<MyInt>
|
||||
{
|
||||
bool operator<(const MyInt& x) const;
|
||||
bool operator==(const MyInt& x) const;
|
||||
MyInt& operator+=(const MyInt& x);
|
||||
MyInt& operator-=(const MyInt& x);
|
||||
MyInt& operator*=(const MyInt& x);
|
||||
MyInt& operator/=(const MyInt& x);
|
||||
MyInt& operator%=(const MyInt& x);
|
||||
MyInt& operator|=(const MyInt& x);
|
||||
MyInt& operator&=(const MyInt& x);
|
||||
MyInt& operator^=(const MyInt& x);
|
||||
MyInt& operator++();
|
||||
MyInt& operator--();
|
||||
};</pre>
|
||||
</blockquote>
|
||||
<p>then the <code>operators<></code> template adds more than a dozen
|
||||
additional operators, such as operator>, <=, >=, and +. <a href="#two_arg">Two-argument
|
||||
forms</a> of the templates are also provided to allow interaction with other
|
||||
types.</p>
|
||||
<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="../../boost/operators.hpp">boost/operators.hpp</a>.<br>
|
||||
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||
contributed the <a href="#deref and helpers">dereference operators and iterator
|
||||
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>
|
||||
contributed the code to support <a href="#chaining">base class chaining</a>
|
||||
while remaining backward-compatible with old versions of the library.<br>
|
||||
<a href="http://www.boost.org/people/beman_dawes.html">Beman Dawes</a>
|
||||
contributed <a href="http://www.boost.org/libs/utility/operators_test.cpp">test_operators.cpp</a>.</p>
|
||||
<h2>Rationale</h2>
|
||||
<p>Overloaded operators for class types typically occur in groups. If you can
|
||||
write <code>x + y</code>, you probably also want to be able to write <code>x +=
|
||||
y</code>. If you can write <code>x < y,</code> you also want <code>x > y,
|
||||
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
|
||||
terms of others (e.g. <code>x >= y <b><=></b> !(x < y)</code>).
|
||||
Replicating this boilerplate for multiple classes is both tedious and
|
||||
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
|
||||
operators you've defined in your class.</p>
|
||||
<a name="two_arg">
|
||||
<h2>Two-Argument Template Forms</h2>
|
||||
</a>
|
||||
<p>The arguments to a binary operator commonly have identical types, but it is
|
||||
not unusual to want to define operators which combine different types. For <a href="#usage">example</a>,
|
||||
one might want to multiply a mathematical vector by a scalar. The two-argument
|
||||
template forms of the arithmetic operator templates are supplied for this
|
||||
purpose. When applying the two-argument form of a template, the desired return
|
||||
type of the operators typically determines which of the two types in question
|
||||
should be derived from the operator template. For example, if the result of <code>T + U</code>
|
||||
is of type <code>T</code>, then <code>T</code> (not <code>U</code>) should be
|
||||
derived from <code>addable<T,U></code>. The comparison templates <code><a href="#less_than_comparable">less_than_comparable<></a></code>
|
||||
and <code><a href="#equality_comparable">equality_comparable<></a></code>
|
||||
are exceptions to this guideline, since the return type of the operators they
|
||||
define is <code>bool</code>.</p>
|
||||
<p>On compilers which do not support partial specialization, the two-argument
|
||||
forms must be specified by using the names shown below with the trailing <code>'2'</code>.
|
||||
The single-argument forms with the trailing <code>'1'</code> are provided for
|
||||
symmetry and to enable certain applications of the <a href="#chaining">base
|
||||
class chaining</a> technique.</p>
|
||||
<h2>Arithmetic operators table</h2>
|
||||
<p>The requirements for the types used to instantiate operator templates are
|
||||
specified in terms of expressions which must be valid and by the return type of
|
||||
the expression. In the following table <code>t</code> and <code>t1</code> are
|
||||
values of type <code>T</code>, and <code>u</code> is a value of type <code>U</code>.
|
||||
Every template in the library other than <a href="#operators"><code>operators<></code></a>
|
||||
and <a href="#operators"><code>operators2<></code></a> has an additional
|
||||
optional template parameter <code>B</code> which is not shown in the table, but
|
||||
is explained <a href="#chaining">below</a></p>
|
||||
<table cellpadding="5" border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><b>template</b></td>
|
||||
<td><b>template will supply</b></td>
|
||||
<td><b>Requirements</b></td>
|
||||
</tr>
|
||||
<a name="operators">
|
||||
<tr>
|
||||
<td><code>operators<T></code></td>
|
||||
<td>All the other <T> templates in this table.</td>
|
||||
<td>All the <T> requirements in this table.</td>
|
||||
<tr>
|
||||
<td><code>operators<T,U><br>
|
||||
operators2<T,U></code></td>
|
||||
<td>All the other <T,U> templates in this table, plus incrementable<T>
|
||||
and decrementable<T>.</td>
|
||||
<td><b>All</b> the <T,U> requirements in this table</a><a href="#portability">*</a>,
|
||||
plus incrementable<T> and decrementable<T>.</td>
|
||||
</tr>
|
||||
<a name="less_than_comparable">
|
||||
<tr>
|
||||
<td><code>less_than_comparable<T><br>
|
||||
less_than_comparable1<T></code></td>
|
||||
<td><code>bool operator>(const T&, const T&) <br>
|
||||
bool operator<=(const T&, const T&)<br>
|
||||
bool operator>=(const T&, const T&)</code></td>
|
||||
<td><code>t<t1</code>. Return convertible to bool</td>
|
||||
<tr>
|
||||
<td><code>less_than_comparable<T,U><br>
|
||||
less_than_comparable2<T,U></code></td>
|
||||
<td><code>bool operator<=(const T&, const U&)<br>
|
||||
bool operator>=(const T&, const U&)<br>
|
||||
bool operator>(const U&, const T&) <br>
|
||||
bool operator<(const U&, const T&) <br>
|
||||
bool operator<=(const U&, const T&)<br>
|
||||
bool operator>=(const U&, const T&)</code></td>
|
||||
<td><code>t<u</code>. Return convertible to bool<br>
|
||||
<code>t>u</code>. Return convertible to bool</td>
|
||||
</tr>
|
||||
</a><a name="equality_comparable">
|
||||
<tr>
|
||||
<td><code>equality_comparable<T><br>
|
||||
equality_comparable1<T></code></td>
|
||||
<td><code>bool operator!=(const T&, const T&)</code></td>
|
||||
<td><code>t==t1</code>. Return convertible to bool</td>
|
||||
<tr>
|
||||
<td><code>equality_comparable<T,U><br>
|
||||
equality_comparable2<T,U></code></td>
|
||||
<td><code>friend bool operator==(const U&, const T&)<br>
|
||||
friend bool operator!=(const U&, const T&)<br>
|
||||
friend bool operator!=( const T&, const U&)</code></td>
|
||||
<td><code>t==u</code>. Return convertible to bool</td>
|
||||
</tr>
|
||||
</a>
|
||||
<tr>
|
||||
<td><code>addable<T><br>
|
||||
addable1<T></code></td>
|
||||
<td><code>T operator+(T, const T&)</code></td>
|
||||
<td><code>t+=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>addable<T,U><br>
|
||||
addable2<T,U></code></td>
|
||||
<td><code>T operator+(T, const U&)<br>
|
||||
T operator+(const U&, T )</code></td>
|
||||
<td><code>t+=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>subtractable<T><br>
|
||||
subtractable1<T></code></td>
|
||||
<td><code>T operator-(T, const T&)</code></td>
|
||||
<td><code>t-=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>subtractable<T,U><br>
|
||||
subtractable2<T,U></code></td>
|
||||
<td><code>T operator-(T, const U&)</code></td>
|
||||
<td><code>t-=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>multipliable<T><br>
|
||||
multipliable1<T></code></td>
|
||||
<td><code>T operator*(T, const T&)</code></td>
|
||||
<td><code>t*=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>multipliable<T,U><br>
|
||||
multipliable2<T,U></code></td>
|
||||
<td><code>T operator*(T, const U&)<br>
|
||||
T operator*(const U&, T )</code></td>
|
||||
<td><code>t*=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>dividable<T><br>
|
||||
dividable1<T></code></td>
|
||||
<td><code>T operator/(T, const T&)</code></td>
|
||||
<td><code>t/=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>dividable<T,U><br>
|
||||
dividable2<T,U></code></td>
|
||||
<td><code>T operator/(T, const U&)</code></td>
|
||||
<td><code>t/=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>modable<T><br>
|
||||
modable1<T></code></td>
|
||||
<td><code>T operator%(T, const T&)</code></td>
|
||||
<td><code>t%=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>modable<T,U><br>
|
||||
modable2<T,U></code></td>
|
||||
<td><code>T operator%(T, const U&)</code></td>
|
||||
<td><code>t%=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>orable<T><br>
|
||||
orable1<T></code></td>
|
||||
<td><code>T operator|(T, const T&)</code></td>
|
||||
<td><code>t|=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>orable<T,U><br>
|
||||
orable2<T,U></code></td>
|
||||
<td><code>T operator|(T, const U&)<br>
|
||||
T operator|(const U&, T )</code></td>
|
||||
<td><code>t|=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>andable<T><br>
|
||||
andable1<T></code></td>
|
||||
<td><code>T operator&(T, const T&)</code></td>
|
||||
<td><code>t&=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>andable<T,U><br>
|
||||
andable2<T,U></code></td>
|
||||
<td><code>T operator&(T, const U&)<br>
|
||||
T operator&(const U&, T)</code></td>
|
||||
<td><code>t&=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>xorable<T><br>
|
||||
xorable1<T></code></td>
|
||||
<td><code>T operator^(T, const T&)</code></td>
|
||||
<td><code>t^=t1</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>xorable<T,U><br>
|
||||
xorable2<T,U></code></td>
|
||||
<td><code>T operator^(T, const U&)<br>
|
||||
T operator^(const U&, T )</code></td>
|
||||
<td><code>t^=u</code>. Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>incrementable<T><br>
|
||||
incrementable1<T></code></td>
|
||||
<td><code>T operator++(T& x, int)</code></td>
|
||||
<td><code>T temp(x); ++x; return temp;</code><br>
|
||||
Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>decrementable<T><br>
|
||||
decrementable1<T></code></td>
|
||||
<td><code>T operator--(T& x, int)</code></td>
|
||||
<td><code>T temp(x); --x; return temp;</code><br>
|
||||
Return convertible to <code>T</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<b><a name="portability">Portability Note:</a></b> many compilers (e.g. MSVC6.3,
|
||||
GCC 2.95.2) will not enforce the requirements in this table unless the
|
||||
operations which depend on them are actually used. This is not
|
||||
standard-conforming behavior. If you are trying to write portable code it is
|
||||
important not to rely on this bug. In particular, it would be convenient to
|
||||
derive all your classes which need binary operators from the <a href="#operators"><code>operators<></code></a>
|
||||
and <a href="#operators"><code>operators2<></code></a> templates,
|
||||
regardless of whether they implement all the requirements in the table. Even if
|
||||
this works with your compiler today, it may not work tomorrow.
|
||||
<h2><a name="chaining">Base Class Chaining</a> and Object Size</h2>
|
||||
<p>Every template listed in the table except <a href="#operators"><code>operators<></code></a>
|
||||
and <a href="#operators"><code>operators2<></code></a> has an additional
|
||||
optional template parameter <code>B</code>. If supplied, <code>B</code>
|
||||
must be a class type; the resulting class will be publicly derived from B. This
|
||||
can be used to avoid the object size bloat commonly associated with multiple
|
||||
empty base classes (see the <a href="#old_lib_note">note for users of older
|
||||
versions</a> below for more details). To provide support for several groups of
|
||||
operators, use the additional parameter to chain operator templates into a
|
||||
single-base class hierarchy, as in the following <a href="#usage">example</a>.</p>
|
||||
<p><b>Caveat:</b> to chain to a base class which is <i>not</i> a boost operator
|
||||
template when using the <a href="#two_arg">single-argument form</a><a> of a
|
||||
boost operator template, you must specify the operator template with the
|
||||
trailing <code>'1'</code> in its name. Otherwise the library will assume you
|
||||
mean to define a binary operation combining the class you intend to use as a
|
||||
base class and the class you're deriving.</p>
|
||||
<p><b>Borland users</b>: even single-inheritance seems to cause an increase in
|
||||
object size in some cases. If you are not defining a template, you may get
|
||||
better object-size performance by avoiding derivation altogether, and instead
|
||||
explicitly instantiating the operator template as follows:
|
||||
<pre>
|
||||
class myclass // lose the inheritance...
|
||||
{
|
||||
//...
|
||||
};
|
||||
// explicitly instantiate the operators I need.
|
||||
template class less_than_comparable<myclass>;
|
||||
template class equality_comparable<myclass>;
|
||||
template class incrementable<myclass>;
|
||||
template class decrementable<myclass>;
|
||||
template class addable<myclass,long>;
|
||||
template class subtractable<myclass,long>;
|
||||
</pre>
|
||||
</a><a name="usage">
|
||||
<h2>Usage example</h2>
|
||||
</a>
|
||||
<pre>template <class T>
|
||||
class point // note: private inheritance is OK here!
|
||||
: boost::addable< point<T> // point + point
|
||||
, boost::subtractable< point<T> // point - point
|
||||
, boost::dividable2< point<T>, T // point / T
|
||||
, boost::multipliable2< point<T>, T // point * T, T * point
|
||||
> > > >
|
||||
{
|
||||
public:
|
||||
point(T, T);
|
||||
T x() const;
|
||||
T y() const;
|
||||
|
||||
point operator+=(const point&);
|
||||
// point operator+(point, const point&) automatically
|
||||
// generated by addable.
|
||||
|
||||
point operator-=(const point&);
|
||||
// point operator-(point, const point&) automatically
|
||||
// generated by subtractable.
|
||||
|
||||
point operator*=(T);
|
||||
// point operator*(point, const T&) and
|
||||
// point operator*(const T&, point) auto-generated
|
||||
// by multipliable.
|
||||
|
||||
point operator/=(T);
|
||||
// point operator/(point, const T&) auto-generated
|
||||
// by dividable.
|
||||
private:
|
||||
T x_;
|
||||
T y_;
|
||||
};
|
||||
|
||||
// now use the point<> class:
|
||||
|
||||
template <class T>
|
||||
T length(const point<T> p)
|
||||
{
|
||||
return sqrt(p.x()*p.x() + p.y()*p.y());
|
||||
}
|
||||
|
||||
const point<float> right(0, 1);
|
||||
const point<float> up(1, 0);
|
||||
const point<float> pi_over_4 = up + right;
|
||||
const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);</pre>
|
||||
<h2>Arithmetic operators demonstration and test program</h2>
|
||||
<p>The <a href="http://www.boost.org/libs/utility/operators_test.cpp">operators_test.cpp</a>
|
||||
program demonstrates the use of the arithmetic operator templates, and can also
|
||||
be used to verify correct operation.</p>
|
||||
<p>The test program has been compiled and run successfully with: </p>
|
||||
<ul>
|
||||
<li>GCC 2.95.2
|
||||
<li>GCC 2.95.2 / STLport 4.0b8.
|
||||
<li>Metrowerks Codewarrior 5.3
|
||||
<li>KAI C++ 3.3
|
||||
<li>Microsoft Visual C++ 6.0 SP3.
|
||||
<li>Microsoft Visual C++ 6.0 SP3 / STLport 4.0b8.</li>
|
||||
</ul>
|
||||
<h1><a name="deref and helpers">Dereference</a> operators and iterator helpers</h1>
|
||||
<p>The <a href="#Iterator helpers">iterator helper</a> templates ease the task
|
||||
of creating a custom iterator. Similar to arithmetic types, a complete iterator
|
||||
has many operators that are "redundant" and can be implemented in
|
||||
terms of the core set of operators.</p>
|
||||
<p>The <a href="#dereference">dereference operators</a> were motivated by the <a href="#Iterator helpers">iterator
|
||||
helpers</a>, but are often useful in non-iterator contexts as well. Many of the
|
||||
redundant iterator operators are also arithmetic operators, so the iterator
|
||||
helper classes borrow many of the operators defined above. In fact, only two new
|
||||
operators need to be defined! (the pointer-to-member <code>operator-></code>
|
||||
and the subscript <code>operator[]</code>). </PP>
|
||||
<h3>Notation</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top"><code>T</code></td>
|
||||
<td valign="top">is the user-defined type for which the operations are
|
||||
being supplied.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>V</code></td>
|
||||
<td valign="top">is the type which the resulting <code>dereferenceable</code>
|
||||
type "points to", or the <code>value_type</code> of the custom
|
||||
iterator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>D</code></td>
|
||||
<td valign="top">is the type used to index the resulting <code>indexable</code>
|
||||
type or the <code>difference_type</code> of the custom iterator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>P</code></td>
|
||||
<td valign="top">is a type which can be dereferenced to access <code>V</code>,
|
||||
or the <code>pointer</code> type of the custom iterator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>R</code></td>
|
||||
<td valign="top">is the type returned by indexing the <code>indexable</code>
|
||||
type or the <code>reference</code> type of the custom iterator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>i</code></td>
|
||||
<td valign="top">is short for <code>static_cast<const T&>(*this)</code>,
|
||||
where <code>this</code> is a pointer to the helper class.<br>
|
||||
Another words, <code>i</code> should be an object of the custom iterator
|
||||
type.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>x,x1,x2</code></td>
|
||||
<td valign="top">are objects of type <code>T</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><code>n</code></td>
|
||||
<td valign="top">is an object of type <code>D</code>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The requirements for the types used to instantiate the dereference operators
|
||||
and iterator helpers are specified in terms of expressions which must be valid
|
||||
and their return type. </p>
|
||||
<h2><a name="dereference">Dereference operators</a></h2>
|
||||
<p>The dereference operator templates in this table all accept an optional
|
||||
template parameter (not shown) to be used for <a href="#chaining">base class
|
||||
chaining</a>.
|
||||
<table cellpadding="5" border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><b>template</b></td>
|
||||
<td><b>template will supply</b></td>
|
||||
<td><b>Requirements</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>dereferenceable<T,P></code></td>
|
||||
<td><code>P operator->() const</code></td>
|
||||
<td><code>(&*i.)</code>. Return convertible to <code>P</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>indexable<T,D,R></code></td>
|
||||
<td><code>R operator[](D n) const</code></td>
|
||||
<td><code>*(i + n)</code>. Return of type <code>R</code>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2><a name="Iterator helpers">Iterator</a> helpers</h2>
|
||||
<p>There are three separate iterator helper classes, each for a different
|
||||
category of iterator. Here is a summary of the core set of operators that the
|
||||
custom iterator must define, and the extra operators that are created by the
|
||||
helper classes. For convenience, the helper classes also fill in all of the
|
||||
typedef's required of iterators by the C++ standard (<code>iterator_category</code>,
|
||||
<code>value_type</code>, etc.).</p>
|
||||
<table cellpadding="5" border="1" valign="top">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><b>template</b></td>
|
||||
<td><b>template will supply</b></td>
|
||||
<td><b>Requirements</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>forward_iterator_helper</code><br>
|
||||
<code><T,V,D,P,R></code></td>
|
||||
<td><code>bool operator!=(const T& x1, const T& x2)</code><br>
|
||||
<code>T operator++(T& x, int)</code><br>
|
||||
<code>V* operator->() const</code><br>
|
||||
</td>
|
||||
<td><code>x1==x2</code>. Return convertible to bool<br>
|
||||
<code>T temp(x); ++x; return temp;</code><br>
|
||||
<code>(&*i.)</code>. Return convertible to <code>V*</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>bidirectional_iterator_helper</code><br>
|
||||
<code><T,V,D,P,R></code></td>
|
||||
<td>Same as above, plus<br>
|
||||
<code>T operator--(T& x, int)</code></td>
|
||||
<td>Same as above, plus<br>
|
||||
<code>T temp(x); --x; return temp;</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>random_access_iterator_helper</code><br>
|
||||
<code><T,V,D,P,R></code></td>
|
||||
<td>Same as above, plus<br>
|
||||
<code>T operator+(T x, const D&)<br>
|
||||
T operator+(const D& n, T x)<br>
|
||||
T operator-(T x, const D& n)<br>
|
||||
R operator[](D n) const<br>
|
||||
bool operator>(const T& x1, const T& x2) <br>
|
||||
bool operator<=(const T& x1, const T& x2)<br>
|
||||
bool operator>=(const T& x1, const T& x2)</code></td>
|
||||
<td>Same as above, plus<br>
|
||||
<code>x+=n</code>. Return convertible to <code>T</code><br>
|
||||
<code>x-=n</code>. Return convertible to <code>T</code><br>
|
||||
<code>x1<x2</code>. Return convertible to bool<br>
|
||||
And to satisfy <a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">RandomAccessIterator</a>:<br>
|
||||
<code>x1-x2</code>. Return convertible to <code>D</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Iterator demonstration and test program</h2>
|
||||
<p>The <a href="http://www.boost.org/libs/utility/iterators_test.cpp">iterators_test.cpp</a>
|
||||
program demonstrates the use of the iterator templates, and can also be used to
|
||||
verify correct operation. The following is the custom iterator defined in the
|
||||
test program. It demonstrates a correct (though trivial) implementation of the
|
||||
core operations that must be defined in order for the iterator helpers to
|
||||
"fill in" the rest of the iterator operations.</p>
|
||||
<blockquote>
|
||||
<pre>template <class T, class R, class P>
|
||||
struct test_iter
|
||||
: public boost::random_access_iterator_helper<
|
||||
test_iter<T,R,P>, T, std::ptrdiff_t, P, R>
|
||||
{
|
||||
typedef test_iter self;
|
||||
typedef R Reference;
|
||||
typedef std::ptrdiff_t Distance;
|
||||
|
||||
public:
|
||||
test_iter(T* i) : _i(i) { }
|
||||
test_iter(const self& x) : _i(x._i) { }
|
||||
self& operator=(const self& x) { _i = x._i; return *this; }
|
||||
Reference operator*() const { return *_i; }
|
||||
self& operator++() { ++_i; return *this; }
|
||||
self& operator--() { --_i; return *this; }
|
||||
self& operator+=(Distance n) { _i += n; return *this; }
|
||||
self& operator-=(Distance n) { _i -= n; return *this; }
|
||||
bool operator==(const self& x) const { return _i == x._i; }
|
||||
bool operator<(const self& x) const { return _i < x._i; }
|
||||
friend Distance operator-(const self& x, const self& y) {
|
||||
return x._i - y._i;
|
||||
}
|
||||
protected:
|
||||
T* _i;
|
||||
};</pre>
|
||||
</blockquote>
|
||||
<p>It has been compiled and run successfully with:</p>
|
||||
<ul>
|
||||
<li>GCC 2.95.2
|
||||
<li>Metrowerks Codewarrior 5.2
|
||||
<li>Microsoft Visual C++ 6.0 SP3</li>
|
||||
</ul>
|
||||
<p><a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||
contributed the iterator operators and helpers. He also contributed <a href="http://www.boost.org/libs/utility/iterators_test.cpp">iterators_test.cpp</a>. </p>
|
||||
<hr>
|
||||
<h2><a name="old_lib_note">Note for users of older versions</a></h2>
|
||||
<p>The <a href="#chaining">changes in the library interface and recommended
|
||||
usage</a> were motivated by some practical issues described below. The new
|
||||
version of the library is still backward-compatible with the former one (so
|
||||
you're not <i>forced</i> change any existing code), but the old usage is
|
||||
deprecated. Though it was arguably simpler and more intuitive than using <a href="#chaining">base
|
||||
class chaining</a>, it has been discovered that the old practice of deriving
|
||||
from multiple operator templates can cause the resulting classes to be much
|
||||
larger than they should be. Most modern C++ compilers significantly bloat the
|
||||
size of classes derived from multiple empty base classes, even though the base
|
||||
classes themselves have no state. For instance, the size of <code>point<int></code>
|
||||
from the <a href="#usage">example</a> above was 12-24 bytes on various compilers
|
||||
for the Win32 platform, instead of the expected 8 bytes.
|
||||
<p>Strictly speaking, it was not the library's fault - the language rules allow
|
||||
the compiler to apply the empty base class optimization in that situation. In
|
||||
principle an arbitrary number of empty base classes can be allocated at the same
|
||||
offset, provided that none of them have a common ancestor (see section 10.5 [class.derived],
|
||||
par. 5 of the standard). But the language definition also doesn't <i>require</i>
|
||||
implementations to do the optimization, and few if any of today's compilers
|
||||
implement it when multiple inheritance is involved. What's worse, it is very
|
||||
unlikely that implementors will adopt it as a future enhancement to existing
|
||||
compilers, because it would break binary compatibility between code generated by
|
||||
two different versions of the same compiler. As Matt Austern said, "One of
|
||||
the few times when you have the freedom to do this sort of thing is when you're
|
||||
targeting a new architecture...". On the other hand, many common compilers
|
||||
will use the empty base optimization for single inheritance hierarchies.</p>
|
||||
<p>Given the importance of the issue for the users of the library (which aims to
|
||||
be useful for writing light-weight classes like <code>MyInt</code> or <code>point<></code>),
|
||||
and the forces described above, we decided to change the library interface so
|
||||
that the object size bloat could be eliminated even on compilers that support
|
||||
only the simplest form of the empty base class optimization. The current library
|
||||
interface is the result of those changes. Though the new usage is a bit more
|
||||
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
|
||||
usage idiom while allowing the library remain backward-compatible.</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->10 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14373" --></p>
|
||||
<p><EFBFBD> Copyright David Abrahams and Beman Dawes 1999-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>
|
391
projection_iterator.htm
Normal file
391
projection_iterator.htm
Normal file
@@ -0,0 +1,391 @@
|
||||
<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>Projection Iterator Adaptor 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>Projection Iterator Adaptor</h1>
|
||||
|
||||
Defined in header
|
||||
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
<p>
|
||||
The projection iterator adaptor is similar to the <a
|
||||
href="./transform_iterator.htm">transform iterator adaptor</a> in that
|
||||
its <tt>operator*()</tt> applies some function to the result of
|
||||
dereferencing the base iterator and then returns the result. The
|
||||
difference is that the function must return a reference to some
|
||||
existing object (for example, a data member within the
|
||||
<tt>value_type</tt> of the base iterator). The following
|
||||
<b>pseudo-code</b> gives the basic idea. The data member <tt>p</tt> is
|
||||
the function object.
|
||||
|
||||
<pre>
|
||||
reference projection_iterator::operator*() const {
|
||||
return this->p(*this->base_iterator);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
struct projection_iterator_generator;
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>,
|
||||
class BaseIterator, class ConstBaseIterator>
|
||||
struct projection_iterator_pair_generator;
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type
|
||||
make_projection_iterator(BaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type
|
||||
make_const_projection_iterator(ConstBaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="projection_iterator_generator">The Projection Iterator Type
|
||||
Generator</a></h2>
|
||||
|
||||
The class <tt>projection_iterator_generator</tt> is a helper class
|
||||
whose purpose is to construct an projection iterator type. The main
|
||||
template parameter for this class is the <a
|
||||
href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a>
|
||||
function object type and the <tt>BaseIterator</tt> type that is being
|
||||
wrapped.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
class projection_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting projection iterator type
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In the following example we have a list of personnel records. Each
|
||||
record has an employee's name and ID number. We want to be able to
|
||||
traverse through the list accessing either the name or the ID numbers
|
||||
of the employees using the projection iterator so we create the
|
||||
function object classes <tt>select_name</tt> and
|
||||
<tt>select_ID</tt>. We then use the
|
||||
<tt>projection_iterator_generator</tt> class to create a projection
|
||||
iterator and use it to print out the names of the employees.
|
||||
|
||||
<pre>
|
||||
#include <boost/config.hpp>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
struct personnel_record {
|
||||
personnel_record(std::string n, int id) : m_name(n), m_ID(id) { }
|
||||
std::string m_name;
|
||||
int m_ID;
|
||||
};
|
||||
|
||||
struct select_name {
|
||||
typedef personnel_record argument_type;
|
||||
typedef std::string result_type;
|
||||
const std::string& operator()(const personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
std::string& operator()(personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
};
|
||||
|
||||
struct select_ID {
|
||||
typedef personnel_record argument_type;
|
||||
typedef int result_type;
|
||||
const int& operator()(const personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
int& operator()(personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
std::list<personnel_record> personnel_list;
|
||||
|
||||
personnel_list.push_back(personnel_record("Barney", 13423));
|
||||
personnel_list.push_back(personnel_record("Fred", 12343));
|
||||
personnel_list.push_back(personnel_record("Wilma", 62454));
|
||||
personnel_list.push_back(personnel_record("Betty", 20490));
|
||||
|
||||
// Example of using projection_iterator_generator
|
||||
// to print out the names in the personnel list.
|
||||
|
||||
boost::projection_iterator_generator<select_name,
|
||||
std::list<personnel_record>::iterator>::type
|
||||
personnel_first(personnel_list.begin()),
|
||||
personnel_last(personnel_list.end());
|
||||
|
||||
std::copy(personnel_first, personnel_last,
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output for this part is:
|
||||
<pre>
|
||||
Barney
|
||||
Fred
|
||||
Wilma
|
||||
Betty
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
|
||||
<TD>The type of the function object. The <tt>argument_type</tt> of the
|
||||
function must match the value type of the base iterator. The function
|
||||
should return a reference to the function's <tt>result_type</tt>.
|
||||
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
|
||||
</TD>
|
||||
</TD>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
If the base iterator is a model of <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so is the resulting projection iterator. If
|
||||
the base iterator supports less functionality than this the resulting
|
||||
projection iterator will also support less functionality.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The projection iterator type implements the member functions and
|
||||
operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> concept.
|
||||
In addition it has the following constructor:
|
||||
|
||||
<pre>
|
||||
projection_iterator_generator::type(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<h2><a name="projection_iterator_pair_generator">The Projection Iterator Pair
|
||||
Generator</a></h2>
|
||||
|
||||
Sometimes a mutable/const pair of iterator types is needed, such as
|
||||
when implementing a container type. The
|
||||
<tt>projection_iterator_pair_generator</tt> class makes it more
|
||||
convenient to create this pair of iterator types.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator, class ConstBaseIterator>
|
||||
class projection_iterator_pair_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> iterator; // the mutable projection iterator type
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> const_iterator; // the immutable projection iterator type
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this part of the example we use the
|
||||
<tt>projection_iterator_pair_generator</tt> to create a mutable/const
|
||||
pair of projection iterators that access the ID numbers of the
|
||||
personnel. We use the mutable iterator to re-index the ID numbers from
|
||||
zero. We then use the constant iterator to print the ID numbers out.
|
||||
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
typedef boost::projection_iterator_pair_generator<select_ID,
|
||||
std::list<personnel_record>::iterator,
|
||||
std::list<personnel_record>::const_iterator> PairGen;
|
||||
|
||||
PairGen::iterator ID_first(personnel_list.begin()),
|
||||
ID_last(personnel_list.end());
|
||||
|
||||
int new_id = 0;
|
||||
while (ID_first != ID_last) {
|
||||
*ID_first = new_id++;
|
||||
++ID_first;
|
||||
}
|
||||
|
||||
PairGen::const_iterator const_ID_first(personnel_list.begin()),
|
||||
const_ID_last(personnel_list.end());
|
||||
|
||||
std::copy(const_ID_first, const_ID_last,
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
0 1 2 3
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
|
||||
<TD>The type of the function object. The <tt>argument_type</tt> of the
|
||||
function must match the value type of the base iterator. The function
|
||||
should return a true reference to the function's <tt>result_type</tt>.
|
||||
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
|
||||
</TD>
|
||||
</TD>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The mutable iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>ConstBaseIterator</tt></TD>
|
||||
<TD>The constant iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
If the base iterator types model the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so do the resulting projection iterator
|
||||
types. If the base iterators support less functionality the
|
||||
resulting projection iterator types will also support less
|
||||
functionality. The resulting <tt>iterator</tt> type is mutable, and
|
||||
the resulting <tt>const_iterator</tt> type is constant.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types
|
||||
implements the member functions and operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> concept. In addition they support the following
|
||||
constructors:
|
||||
|
||||
<pre>
|
||||
projection_iterator_pair_generator::iterator(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())</pre>
|
||||
|
||||
<pre>
|
||||
projection_iterator_pair_generator::const_iterator(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<h2><a name="make_projection_iterator">The Projection Iterator Object Generators</a></h2>
|
||||
|
||||
The <tt>make_projection_iterator()</tt> and
|
||||
<tt>make_const_projection_iterator()</tt> functions provide a more
|
||||
convenient way to create projection iterator objects. The functions
|
||||
save the user the trouble of explicitly writing out the iterator
|
||||
types.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type
|
||||
make_projection_iterator(BaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type
|
||||
make_const_projection_iterator(ConstBaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this part of the example, we again print out the names of the
|
||||
personnel, but this time we use the
|
||||
<tt>make_const_projection_iterator()</tt> function to save some typing.
|
||||
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
std::copy
|
||||
(boost::make_const_projection_iterator<select_name>(personnel_list.begin()),
|
||||
boost::make_const_projection_iterator<select_name>(personnel_list.end()),
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
Barney
|
||||
Fred
|
||||
Wilma
|
||||
Betty
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></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>
|
||||
<!-- LocalWords: html charset alt gif hpp BaseIterator const namespace struct
|
||||
-->
|
||||
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
|
||||
-->
|
||||
<!-- LocalWords: sizeof PairGen pre Siek htm AdaptableUnaryFunction
|
||||
-->
|
||||
<!-- LocalWords: ConstBaseIterator
|
||||
-->
|
96
projection_iterator_example.cpp
Normal file
96
projection_iterator_example.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
struct personnel_record {
|
||||
personnel_record(std::string n, int id) : m_name(n), m_ID(id) { }
|
||||
std::string m_name;
|
||||
int m_ID;
|
||||
};
|
||||
|
||||
struct select_name {
|
||||
typedef personnel_record argument_type;
|
||||
typedef std::string result_type;
|
||||
const std::string& operator()(const personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
std::string& operator()(personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
};
|
||||
|
||||
struct select_ID {
|
||||
typedef personnel_record argument_type;
|
||||
typedef int result_type;
|
||||
const int& operator()(const personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
int& operator()(personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
std::list<personnel_record> personnel_list;
|
||||
|
||||
personnel_list.push_back(personnel_record("Barney", 13423));
|
||||
personnel_list.push_back(personnel_record("Fred", 12343));
|
||||
personnel_list.push_back(personnel_record("Wilma", 62454));
|
||||
personnel_list.push_back(personnel_record("Betty", 20490));
|
||||
|
||||
// Example of using projection_iterator_generator
|
||||
// to print out the names in the personnel list.
|
||||
|
||||
boost::projection_iterator_generator<select_name,
|
||||
std::list<personnel_record>::iterator>::type
|
||||
personnel_first(personnel_list.begin()),
|
||||
personnel_last(personnel_list.end());
|
||||
|
||||
std::copy(personnel_first, personnel_last,
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using projection_iterator_pair_generator
|
||||
// to assign new ID numbers to the personnel.
|
||||
|
||||
typedef boost::projection_iterator_pair_generator<select_ID,
|
||||
std::list<personnel_record>::iterator,
|
||||
std::list<personnel_record>::const_iterator> PairGen;
|
||||
|
||||
PairGen::iterator ID_first(personnel_list.begin()),
|
||||
ID_last(personnel_list.end());
|
||||
|
||||
int new_id = 0;
|
||||
while (ID_first != ID_last) {
|
||||
*ID_first = new_id++;
|
||||
++ID_first;
|
||||
}
|
||||
|
||||
PairGen::const_iterator const_ID_first(personnel_list.begin()),
|
||||
const_ID_last(personnel_list.end());
|
||||
|
||||
std::copy(const_ID_first, const_ID_last,
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using make_const_projection_iterator()
|
||||
// to print out the names in the personnel list again.
|
||||
|
||||
std::copy
|
||||
(boost::make_const_projection_iterator<select_name>(personnel_list.begin()),
|
||||
boost::make_const_projection_iterator<select_name>(personnel_list.end()),
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
|
||||
return 0;
|
||||
}
|
331
reverse_iterator.htm
Normal file
331
reverse_iterator.htm
Normal file
@@ -0,0 +1,331 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
||||
<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>Reverse Iterator Adaptor 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>Reverse Iterator Adaptor</h1>
|
||||
Defined in header <a href=
|
||||
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
<p>The reverse iterator adaptor flips the direction of a base iterator's
|
||||
motion. Invoking <tt>operator++()</tt> moves the base iterator backward and
|
||||
invoking <tt>operator--()</tt> moves the base iterator forward. The Boost
|
||||
reverse iterator adaptor is better to use than the
|
||||
<tt>std::reverse_iterator</tt> class in situations where pairs of
|
||||
mutable/constant iterators are needed (e.g., in containers) because
|
||||
comparisons and conversions between the mutable and const versions are
|
||||
implemented correctly.
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class <a href=
|
||||
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
|
||||
class Value, class Reference, class Pointer, class Category, class Distance>
|
||||
struct reverse_iterator_generator;
|
||||
|
||||
template <class <a href=
|
||||
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>>
|
||||
typename reverse_iterator_generator<BidirectionalIterator>::type
|
||||
make_reverse_iterator(BidirectionalIterator base)
|
||||
}
|
||||
</pre>
|
||||
<hr>
|
||||
|
||||
<h2><a name="reverse_iterator_generator">The Reverse Iterator Type
|
||||
Generator</a></h2>
|
||||
The <tt>reverse_iterator_generator</tt> template is a <a href=
|
||||
"../../more/generic_programming.html#type_generator">generator</a> of
|
||||
reverse iterator types. The main template parameter for this class is the
|
||||
base <tt>BidirectionalIterator</tt> type that is being adapted. In most
|
||||
cases the associated types of the base iterator can be deduced using
|
||||
<tt>std::iterator_traits</tt>, but in some situations the user may want to
|
||||
override these types, so there are also template parameters for the base
|
||||
iterator's associated types.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class <a href=
|
||||
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
|
||||
class Value, class Reference, class Pointer, class Category, class Distance>
|
||||
class reverse_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href=
|
||||
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting reverse iterator type
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
In this example we sort a sequence of letters and then output the sequence
|
||||
in descending order using reverse iterators.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
char letters[] = "hello world!";
|
||||
const int N = sizeof(letters)/sizeof(char) - 1;
|
||||
std::cout << "original sequence of letters:\t"
|
||||
<< letters << std::endl;
|
||||
|
||||
std::sort(letters, letters + N);
|
||||
|
||||
// Use reverse_iterator_generator to print a sequence
|
||||
// of letters in reverse order.
|
||||
|
||||
boost::reverse_iterator_generator<char*>::type
|
||||
reverse_letters_first(letters + N),
|
||||
reverse_letters_last(letters);
|
||||
|
||||
std::cout << "letters in descending order:\t";
|
||||
std::copy(reverse_letters_first, reverse_letters_last,
|
||||
std::ostream_iterator<char>(std::cout));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
</blockquote>
|
||||
The output is:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
original sequence of letters: hello world!
|
||||
letters in descending order: wroolllhed!
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<table border>
|
||||
<tr>
|
||||
<th>Parameter
|
||||
|
||||
<th>Description
|
||||
|
||||
<tr>
|
||||
<td><tt><a href=
|
||||
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a></tt>
|
||||
|
||||
|
||||
<td>The iterator type being wrapped.
|
||||
|
||||
<tr>
|
||||
<td><tt>Value</tt>
|
||||
|
||||
<td>The value-type of the base iterator and the resulting reverse
|
||||
iterator.<br>
|
||||
<b>Default:</b><tt>std::iterator_traits<BidirectionalIterator>::value_type</tt>
|
||||
|
||||
|
||||
<tr>
|
||||
<td><tt>Reference</tt>
|
||||
|
||||
<td>The <tt>reference</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator*()</tt>.<br>
|
||||
<b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&</tt> is
|
||||
used. Otherwise
|
||||
<tt>std::iterator_traits<BidirectionalIterator>::reference</tt>
|
||||
is used.
|
||||
|
||||
<tr>
|
||||
<td><tt>Pointer</tt>
|
||||
|
||||
<td>The <tt>pointer</tt> type of the resulting iterator, and in
|
||||
particular, the result type of <tt>operator->()</tt>.<br>
|
||||
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
|
||||
otherwise
|
||||
<tt>std::iterator_traits<BidirectionalIterator>::pointer</tt>.
|
||||
|
||||
<tr>
|
||||
<td><tt>Category</tt>
|
||||
|
||||
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
|
||||
<b>Default:</b>
|
||||
<tt>std::iterator_traits<BidirectionalIterator>::iterator_category</tt>
|
||||
|
||||
|
||||
<tr>
|
||||
<td><tt>Distance</tt>
|
||||
|
||||
<td>The <tt>difference_type</tt> for the resulting iterator.<br>
|
||||
<b>Default:</b>
|
||||
<tt>std::iterator_traits<BidirectionalIterator&gt::difference_type</tt>
|
||||
|
||||
</table>
|
||||
|
||||
<h3>Concept Model</h3>
|
||||
The indirect iterator will model whichever <a href=
|
||||
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator concept
|
||||
category</a> is modeled by the base iterator. Thus, if the base iterator is
|
||||
a model of <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
|
||||
Iterator</a> then so is the resulting indirect iterator. If the base
|
||||
iterator models a more restrictive concept, the resulting indirect iterator
|
||||
will model the same concept. The base iterator must be at least a <a href=
|
||||
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional
|
||||
Iterator</a>
|
||||
|
||||
<h3>Members</h3>
|
||||
The reverse iterator type implements the member functions and operators
|
||||
required of the <a href=
|
||||
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
|
||||
Iterator</a> concept. In addition it has the following constructor:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
reverse_iterator_generator::type(const BidirectionalIterator& it)
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
|
||||
<h2><a name="make_reverse_iterator">The Reverse Iterator Object
|
||||
Generator</a></h2>
|
||||
The <tt>make_reverse_iterator()</tt> function provides a more convenient
|
||||
way to create reverse iterator objects. The function saves the user the
|
||||
trouble of explicitly writing out the iterator types.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class BidirectionalIterator>
|
||||
typename reverse_iterator_generator<BidirectionalIterator>::type
|
||||
make_reverse_iterator(BidirectionalIterator base);
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Example</h3>
|
||||
In this part of the example we use <tt>make_reverse_iterator()</tt> to
|
||||
print the sequence of letters in reverse-reverse order, which is the
|
||||
original order.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// continuing from the previous example...
|
||||
|
||||
std::cout << "letters in ascending order:\t";
|
||||
std::copy(boost::make_reverse_iterator(reverse_letters_last),
|
||||
boost::make_reverse_iterator(reverse_letters_first),
|
||||
std::ostream_iterator<char>(std::cout));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
The output is:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
letters in ascending order: !dehllloorw
|
||||
</pre>
|
||||
</blockquote>
|
||||
<hr>
|
||||
|
||||
<h2><a name="interactions">Constant/Mutable Iterator Interactions</a></h2>
|
||||
|
||||
<p>One failing of the standard <tt><a
|
||||
href="http://www.sgi.com/tech/stl/ReverseIterator.html">reverse_iterator</a></tt>
|
||||
adaptor is that it doesn't properly support interactions between adapted
|
||||
<tt>const</tt> and non-<tt>const</tt> iterators. For example:
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <vector>
|
||||
|
||||
template <class T> void convert(T x) {}
|
||||
|
||||
// Test interactions of a matched pair of random access iterators
|
||||
template <class Iterator, class ConstIterator>
|
||||
void test_interactions(Iterator i, ConstIterator ci)
|
||||
{
|
||||
bool eq = i == ci; // comparisons
|
||||
bool ne = i != ci;
|
||||
bool lt = i < ci;
|
||||
bool le = i <= ci;
|
||||
bool gt = i > ci;
|
||||
bool ge = i >= ci;
|
||||
std::size_t distance = i - ci; // difference
|
||||
ci = i; // assignment
|
||||
ConstIterator ci2(i); // construction
|
||||
convert<ConstIterator>(i); // implicit conversion
|
||||
}
|
||||
|
||||
void f()
|
||||
{
|
||||
typedef std::vector<int> vec;
|
||||
vec v;
|
||||
const vec& cv;
|
||||
|
||||
test_interactions(v.begin(), cv.begin()); // <font color="#007F00">OK</font>
|
||||
test_interactions(v.rbegin(), cv.rbegin()); // <font color="#FF0000">ERRORS ON EVERY TEST!!</font>
|
||||
</pre>
|
||||
</blockquote>
|
||||
Reverse iterators created with <tt>boost::reverse_iterator_generator</tt> don't have this problem, though:
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef boost::reverse_iterator_generator<vec::iterator>::type ri;
|
||||
typedef boost::reverse_iterator_generator<vec::const_iterator>::type cri;
|
||||
test_interactions(ri(v.begin()), cri(cv.begin())); // <font color="#007F00">OK!!</font>
|
||||
</pre>
|
||||
</blockquote>
|
||||
Or, more simply,
|
||||
<blockquote>
|
||||
<pre>
|
||||
test_interactions(
|
||||
boost::make_reverse_iterator(v.begin()),
|
||||
boost::make_reverse_iterator(cv.begin())); // <font color="#007F00">OK!!</font>
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>If you are wondering why there is no
|
||||
<tt>reverse_iterator_pair_generator</tt> in the manner of <tt><a
|
||||
href="projection_iterator.htm#projection_iterator_pair_generator">projection_iterator_pair_generator</a></tt>,
|
||||
the answer is simple: we tried it, but found that in practice it took
|
||||
<i>more</i> typing to use <tt>reverse_iterator_pair_generator</tt> than to
|
||||
simply use <tt>reverse_iterator_generator</tt> twice!<br><br>
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
|
||||
|
||||
|
||||
<p>© 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.
|
||||
<!-- LocalWords: html charset alt gif hpp BidirectionalIterator const namespace struct
|
||||
-->
|
||||
|
||||
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
|
||||
-->
|
||||
<!-- LocalWords: sizeof PairGen pre Siek wroolllhed dehllloorw
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
42
reverse_iterator_example.cpp
Normal file
42
reverse_iterator_example.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
char letters[] = "hello world!";
|
||||
const int N = sizeof(letters)/sizeof(char) - 1;
|
||||
std::cout << "original sequence of letters:\t"
|
||||
<< letters << std::endl;
|
||||
|
||||
std::sort(letters, letters + N);
|
||||
|
||||
// Use reverse_iterator_generator to print a sequence
|
||||
// of letters in reverse order.
|
||||
|
||||
boost::reverse_iterator_generator<char*>::type
|
||||
reverse_letters_first(letters + N),
|
||||
reverse_letters_last(letters);
|
||||
|
||||
std::cout << "letters in descending order:\t";
|
||||
std::copy(reverse_letters_first, reverse_letters_last,
|
||||
std::ostream_iterator<char>(std::cout));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Use make_reverse_iterator() to print the sequence
|
||||
// of letters in reverse-reverse order.
|
||||
|
||||
std::cout << "letters in ascending order:\t";
|
||||
std::copy(boost::make_reverse_iterator(reverse_letters_last),
|
||||
boost::make_reverse_iterator(reverse_letters_first),
|
||||
std::ostream_iterator<char>(std::cout));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
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/tech/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;
|
||||
}
|
75
tmpw2001-paper/Makefile
Normal file
75
tmpw2001-paper/Makefile
Normal file
@@ -0,0 +1,75 @@
|
||||
# -*- makefile -*-
|
||||
|
||||
DVIPS = dvips
|
||||
LATEX = pdflatex
|
||||
LATEXOUT = pdf
|
||||
RESULT = pdf
|
||||
|
||||
#LATEX = latex
|
||||
#LATEXOUT = dvi
|
||||
#RESULT = ps
|
||||
|
||||
.SUFFIXES: .tex .dvi .ps .pdf .c .lg .eps
|
||||
|
||||
.c.lg:
|
||||
lgrind -i -o $*.lg -a -lc++ $*.c
|
||||
|
||||
.eps.pdf:
|
||||
epstopdf $*.eps
|
||||
|
||||
.tex.pdf:
|
||||
@ if test ! -f $*.ind; then echo "" > $*.ind; fi
|
||||
@ $(LATEX) $*
|
||||
@ if ( grep 'Writing index file' $*.log > /dev/null ); \
|
||||
then makeindex $* ; $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Citation' $*.log > /dev/null ); \
|
||||
then bibtex $* ; $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
|
||||
.dvi.ps:
|
||||
$(DVIPS) -o $*.ps $*
|
||||
|
||||
.ps.pdf:
|
||||
distill -v -maxsubsetpct 99 -subsetfonts on -pairs $*.ps $*.pdf
|
||||
|
||||
|
||||
SRCCODE =
|
||||
|
||||
|
||||
#
|
||||
# Default rule
|
||||
#
|
||||
|
||||
default: iter-adaptor.$(RESULT)
|
||||
|
||||
|
||||
#
|
||||
# LaTeX stuff
|
||||
#
|
||||
TEX = iter-adaptor.tex
|
||||
|
||||
iter-adaptor.dvi: $(TEX) $(SRCCODELG)
|
||||
iter-adaptor.ps: iter-adaptor.dvi
|
||||
iter-adaptor.pdf: $(PDFPICT) $(TEX) $(SRCCODELG)
|
||||
|
||||
dist: iter-adaptor.ps iter-adaptor.pdf
|
||||
mkdir -p iter-adaptor
|
||||
cp $(TEX) $(SRCCODELG) $(EPS) $(PS) \
|
||||
iter-adaptor.bbl iter-adaptor.ps iter-adaptor.pdf \
|
||||
iter-adaptor
|
||||
tar cvf - ./iter-adaptor | gzip > iter-adaptor.tar.gz
|
||||
|
||||
#
|
||||
# Standard rules
|
||||
#
|
||||
|
||||
clean:
|
||||
/bin/rm -f *.dvi *.o *.ps *.pdf *.log *.blg *.bbl *.aux *~ *.out *.ind
|
||||
|
36
tmpw2001-paper/defs.tex
Normal file
36
tmpw2001-paper/defs.tex
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
\usepackage{times}
|
||||
|
||||
\newif\ifpdf
|
||||
\ifx\pdfoutput\undefined
|
||||
\pdffalse
|
||||
\else
|
||||
\pdfoutput=1
|
||||
\pdftrue
|
||||
\fi
|
||||
|
||||
\ifpdf
|
||||
\usepackage[
|
||||
pdftex,
|
||||
colorlinks=true,
|
||||
linkcolor=blue,filecolor=blue,pagecolor=blue,urlcolor=blue
|
||||
]{hyperref}
|
||||
\fi
|
||||
|
||||
\ifpdf
|
||||
\newcommand{\concept}[1]{\hyperref[concept:#1]{\textsf{#1}}}
|
||||
\newcommand{\stlconcept}[1]{\href{http://www.sgi.com/tech/stl/#1.html}{\textsf{#1}}}
|
||||
\newcommand{\link}[2]{\hyperref[#1]{#2}}
|
||||
\else
|
||||
\newcommand{\concept}[1]{\textsf{#1}}
|
||||
\newcommand{\stlconcept}[1]{\textsf{#1}}
|
||||
\newcommand{\href}[2]{#2}
|
||||
\newcommand{\link}[2]{#2}
|
||||
\fi
|
||||
|
||||
\newcommand{\code}[1]{{\small \texttt{#1}}}
|
||||
|
||||
\newcommand{\Note}[1]{\marginpar{\begin{flushleft}%
|
||||
{%%\tiny %%\footnotesize
|
||||
{\bf Note:} #1}%
|
||||
\end{flushleft}}}
|
1231
tmpw2001-paper/iter-adaptor.tex
Normal file
1231
tmpw2001-paper/iter-adaptor.tex
Normal file
File diff suppressed because it is too large
Load Diff
102
tmpw2001-paper/netobjectdays.cls
Normal file
102
tmpw2001-paper/netobjectdays.cls
Normal file
@@ -0,0 +1,102 @@
|
||||
% Paper Formatting according to requirements of Net.Objectdays 2000
|
||||
\LoadClass[10pt]{article}
|
||||
\pagestyle{empty}
|
||||
% ---------------------------------------------------------------------
|
||||
\textheight193mm
|
||||
\textwidth122mm
|
||||
\oddsidemargin44mm
|
||||
\hoffset-1in \voffset-1in
|
||||
\topmargin52mm
|
||||
\headsep0pt
|
||||
\headheight0pt
|
||||
% ---------------------------------------------------------------------
|
||||
\renewcommand\maketitle{\par
|
||||
\begingroup
|
||||
\renewcommand\thefootnote{\@fnsymbol\c@footnote}%
|
||||
\def\@makefnmark{\rlap{\@textsuperscript{\normalfont\@thefnmark}}}%
|
||||
\long\def\@makefntext##1{\parindent 1em\noindent
|
||||
\hb@xt@1.8em{%
|
||||
\hss\@textsuperscript{\normalfont\@thefnmark}}##1}%
|
||||
\if@twocolumn
|
||||
\ifnum \col@number=\@ne
|
||||
\@maketitle
|
||||
\else
|
||||
\twocolumn[\@maketitle]%
|
||||
\fi
|
||||
\else
|
||||
\newpage
|
||||
\global\@topnum\z@ % Prevents figures from going at top of page.
|
||||
\@maketitle
|
||||
\fi
|
||||
\thispagestyle{empty}\@thanks
|
||||
\endgroup
|
||||
\setcounter{footnote}{0}%
|
||||
\global\let\thanks\relax
|
||||
\global\let\maketitle\relax
|
||||
\global\let\@maketitle\relax
|
||||
\global\let\@thanks\@empty
|
||||
\global\let\@author\@empty
|
||||
\global\let\@date\@empty
|
||||
\global\let\@title\@empty
|
||||
\global\let\title\relax
|
||||
\global\let\author\relax
|
||||
\global\let\date\relax
|
||||
\global\let\and\relax
|
||||
}
|
||||
\date{}
|
||||
\def\@maketitle{%
|
||||
\newpage
|
||||
\null
|
||||
\vskip 2em%
|
||||
\begin{center}%
|
||||
\let \footnote \thanks
|
||||
{\Large \textbf{\@title} \par}%
|
||||
\vskip 1.5em%
|
||||
{\large
|
||||
\lineskip .5em%
|
||||
{\normalsize
|
||||
\begin{tabular}[t]{c}%
|
||||
\@author
|
||||
\end{tabular}\par}}%
|
||||
\vskip 1em%
|
||||
{\large \@date}%
|
||||
\end{center}%
|
||||
\par
|
||||
\vskip 1.5em}
|
||||
\renewcommand\section{\@startsection {section}{1}{\z@}%
|
||||
{-3.5ex \@plus -1ex \@minus -.2ex}%
|
||||
{2.3ex \@plus.2ex}%
|
||||
{\normalfont\large\bfseries}}
|
||||
\renewcommand\subsection{\@startsection{subsection}{2}{\z@}%
|
||||
{-3.25ex\@plus -1ex \@minus -.2ex}%
|
||||
{1.5ex \@plus .2ex}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%
|
||||
{-3.25ex\@plus -1ex \@minus -.2ex}%
|
||||
{1.5ex \@plus .2ex}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}%
|
||||
{3.25ex \@plus1ex \@minus.2ex}%
|
||||
{-1em}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\subparagraph{\@startsection{subparagraph}{5}{\parindent}%
|
||||
{3.25ex \@plus1ex \@minus .2ex}%
|
||||
{-1em}%
|
||||
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand{\figurename}{Fig}
|
||||
\renewcommand{\tablename}{Tab}
|
||||
\long\def\@makecaption#1#2{%
|
||||
\vskip\abovecaptionskip
|
||||
\sbox\@tempboxa{{\small\textbf{#1.} #2}}%
|
||||
\ifdim \wd\@tempboxa >\hsize
|
||||
{\small\textbf{#1.} #2}\par
|
||||
\else
|
||||
\global \@minipagefalse
|
||||
\hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
|
||||
\fi
|
||||
\vskip\belowcaptionskip}
|
||||
\renewenvironment{abstract}
|
||||
{\list{}{\leftmargin1cm\rightmargin\leftmargin}%
|
||||
\item\relax{\small \textbf{Abstract.}}}
|
||||
{\endlist}
|
124
tmpw2001-paper/refs.bib
Normal file
124
tmpw2001-paper/refs.bib
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
@TechReport{stepa.lee-1994:the.s:TR,
|
||||
author = "A. A. Stepanov and M. Lee",
|
||||
title = "{The Standard Template Library}",
|
||||
institution = "ISO Programming Language C++ Project",
|
||||
year = "1994",
|
||||
number = "X3J16/94-0095, WG21/N0482",
|
||||
month = may,
|
||||
}
|
||||
|
||||
@Book{ austern99:_gener_progr_stl,
|
||||
author = "Matthew H. Austern",
|
||||
title = "Generic Programming and the {STL}",
|
||||
publisher = "Addison-Wesley",
|
||||
year = 1999,
|
||||
series = "Professional computing series"
|
||||
}
|
||||
|
||||
@Book{koenig97:_rumin_cpp,
|
||||
author = {Andrew Koenig and Barbara Moo},
|
||||
title = {Ruminations on {C++}},
|
||||
publisher = {Addison Wesley},
|
||||
year = 1997
|
||||
}
|
||||
|
||||
@Book{iso98:_cpp_final_draft_standard,
|
||||
author = "International Organization for Standardization
|
||||
(ISO)",
|
||||
title = "ISO/IEC Final Draft International Standard 14882:
|
||||
Programming Language C++",
|
||||
year = 1998,
|
||||
address = "1 rue de Varemb\'e, Case postale 56, CH-1211
|
||||
Gen\`eve 20, Switzerland"
|
||||
}
|
||||
|
||||
@Book{alexandrescu01:_modern_cpp_design,
|
||||
author = {Andrei Alexandrescu},
|
||||
title = {Modern {C++} Design},
|
||||
publisher = {Addison Wesley},
|
||||
year = 2001
|
||||
}
|
||||
|
||||
@BOOK { Barton94,
|
||||
AUTHOR = "John Barton and Lee Nackman",
|
||||
TITLE = "Scientific and Engineering {C++}",
|
||||
PUBLISHER = "Addison-Wesley",
|
||||
YEAR = 1994
|
||||
}
|
||||
|
||||
@Book{gamma95:_design_patterns,
|
||||
author = {Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides},
|
||||
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
|
||||
publisher = {Addison-Welsey},
|
||||
year = 1995,
|
||||
series = {Professional Computing}
|
||||
}
|
||||
|
||||
@Book{stroustrup00:_cpp_prog_lang,
|
||||
author = {Bjarne Stroustrup},
|
||||
title = {The {C++} Programming Language},
|
||||
publisher = {Addison-Wesley},
|
||||
year = 2000,
|
||||
edition = {Special}
|
||||
}
|
||||
|
||||
@Article{alexandrescu98:_compound_iters,
|
||||
author = {Andrei Alexandrescu},
|
||||
title = {Compound iterators of {STL}},
|
||||
journal = {{C/C++} Users Journal},
|
||||
year = 1998,
|
||||
volume = 16,
|
||||
number = 10,
|
||||
pages = {79-82},
|
||||
month = October
|
||||
}
|
||||
|
||||
@Article{becker98:_smart_iteraters,
|
||||
author = {Thomas Becker},
|
||||
title = {Smart Iterators and STL},
|
||||
journal = {{C/C++} Users Journal},
|
||||
year = 1998,
|
||||
volume = 16,
|
||||
number = 9,
|
||||
month = {September}
|
||||
}
|
||||
|
||||
@InBook{siek99:_scitools,
|
||||
author = {Jeremy G. Siek and Andrew Lumsdaine},
|
||||
title = {Modern Software Tools for Scientific Computing},
|
||||
chapter = {A Modern Framework for Portable High Performance
|
||||
Numerical Linear Algebra},
|
||||
publisher = {Birkhauser},
|
||||
year = 1999,
|
||||
}
|
||||
|
||||
@TechReport{siek01:_improved_iter_cat,
|
||||
author = {Jeremy Siek},
|
||||
title = {Improved Iterator Categories and Requirements},
|
||||
institution = {ISO IEC JTC1/SC22/WG21 - C++},
|
||||
year = 2001,
|
||||
number = {N1297}
|
||||
}
|
||||
|
||||
@Book{mehlhorn99:_leda,
|
||||
author = {K. Mehlhorn and St. N\"aher},
|
||||
title = {The LEDA Platform of Combinatorial and Geometric Computing},
|
||||
publisher = {Cambridge University Press},
|
||||
year = 1999
|
||||
}
|
||||
|
||||
@Book{ knu94:sgb,
|
||||
author = {D. E. Knuth},
|
||||
title = {Stanford GraphBase: a platform for combinatorial computing},
|
||||
publisher = {ACM Press},
|
||||
year = {1994}
|
||||
}
|
||||
|
||||
@Misc{czarnecki00:_named_param,
|
||||
author = {Krzysztof Czarnecki and Ulrich Eisenecker},
|
||||
title = {Named Parameters for Configuration Generators},
|
||||
howpublished = {http://www.generative-programming.org/namedparams/},
|
||||
year = 2000
|
||||
}
|
||||
|
249
tmpw2001-paper/tmpw00.bib
Normal file
249
tmpw2001-paper/tmpw00.bib
Normal file
@@ -0,0 +1,249 @@
|
||||
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Eisenecker,
|
||||
AUTHOR = "Ulrich W. Eisenecker and Frank Blinn and Krzysztof Czarnecki",
|
||||
TITLE = "A Solution to the Constructor-Problem of Mixin-Based Programming in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Mixin-Based Programming in C++ is a powerful programming style
|
||||
based on the parameterized inheritance idiom and the composition
|
||||
of C++ templates. Type expressions describing specific inheritance
|
||||
hierarchies can be composed either automatically using generative
|
||||
programming idioms in C++ or manually. Unfortunately, the mixin-based
|
||||
C++ programming techniques published to date do not adequately support
|
||||
optional and alternative mixin classes with constructors expecting
|
||||
varying numbers of arguments, which are common in practice. This
|
||||
is because the varying base class constructors do not provide a
|
||||
uniform interface on which the constructors of the derived classes
|
||||
could rely. This paper discusses several partial solutions to this
|
||||
problem that were proposed to date and presents a new, complete
|
||||
solution. The new solution uses generative programming techniques to
|
||||
automatically generate the appropriate constructors, and this way it
|
||||
avoids the overhead and clumsiness of instantiating composed mixin
|
||||
classes in the client code using the partial solutions. In fact,
|
||||
the new solution allows users to instantiate automatically composed
|
||||
mixin classes with the simplicity of instantiating concrete classes
|
||||
from traditional class hierarchies. Finally, the new solution does
|
||||
not suffer from the scalability problems of the partial solutions."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Berti,
|
||||
AUTHOR = "Guntram Berti",
|
||||
TITLE = "Generic Components for Grid Data Structures and Algorithms with {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Grids are fundamental data structures for representing
|
||||
geometric structures or their subdivisions. We propose a strategy
|
||||
for decoupling algorithms working on grids from the details of
|
||||
grid representations, using a generic programming approach in C++.
|
||||
Functionality of grid data structures is captured by a small set of
|
||||
primitives, divided into combinatorial and geometric ones. Special
|
||||
attention is paid to the generic implementation of grid functions, which
|
||||
correspond to the notion of mappings from grid elements (e. g. vertices)
|
||||
to entities of a given type. Experiments indicate that the overhead
|
||||
of the generic formulation is low and can be completely eliminated in
|
||||
some cases."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Veldhuizen,
|
||||
AUTHOR = "Todd L. Veldhuizen",
|
||||
TITLE = "Five compilation models for {C++} templates",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"This paper proposes an alternate structure for C++ compilers.
|
||||
Type analysis is removed from the compiler and replaced with a
|
||||
`type system library' which is treated as source code by the
|
||||
compiler. Type computations are embedded in the intermediate
|
||||
language of the compiler, and partial evaluation is used to drive
|
||||
type analysis and template instantiation. By making simple changes to
|
||||
the behavior of the partial evaluator, a wide range of compilation
|
||||
models is achieved, each with a distinct tradeoff of compile time, code
|
||||
size, and code speed. These models range from pure dynamic typing --
|
||||
ideal for scripting C++ -- to profile-directed template instantiation.
|
||||
This approach may solve several serious problems in compiling C++:
|
||||
it achieves separate compilation of templates, allows template
|
||||
code to be distributed in binary form by deferring template instantiation
|
||||
until run time, and reduces the code bloat associated with
|
||||
templates."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Baus,
|
||||
AUTHOR = "Christopher Baus and Thomas Becker",
|
||||
TITLE = "Custom Iterators for the {STL}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"We discuss several kinds of custom iterators for use with the STL
|
||||
that are substantially different from the iterators that come with
|
||||
the STL. We present class templates that implement these custom
|
||||
iterators in a generic manner."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Weiser,
|
||||
AUTHOR = "Martin Weiser and Gary Powell",
|
||||
TITLE = "The {View Template Library}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Views are container adaptors providing access to different
|
||||
on the fly generated representations of the data in the container they
|
||||
are applied to. The concept fits nicely into the framework defined by
|
||||
the STL. This paper explains design, usage, and implementation of the
|
||||
View Template Library, the currently most advanced implementation of
|
||||
the views concept."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Striegnitz,
|
||||
AUTHOR = "J{\"o}rg Striegnitz and Stephen A. Smith",
|
||||
TITLE = "An Expression Template aware Lambda Function",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Template libraries such as the STL contain several generic algorithms
|
||||
that expect functions as arguments and thereby cause frequent use of
|
||||
function objects. User-defined function objects are awkward because
|
||||
they must be declared as a class in namespace scope before they may
|
||||
be used. In this paper, we describe a lambda function for C++, which
|
||||
allows users to define function objects on the fly, without writing class
|
||||
declarations. We show that, by using expression templates, the lambda
|
||||
function can be implemented without hurting the runtime performance of a
|
||||
program. Expression templates can also help to overcome the performance
|
||||
penalties that may arise when using expressions over user-defined
|
||||
types. Thus, we based our approach on PETE which is a framework
|
||||
that simplifies the addition of expression template functionality to
|
||||
user-defined classes."
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@InProceedings{TMPW00:McNamara,
|
||||
AUTHOR = "Brian McNamara and Yannis Smaragdakis",
|
||||
TITLE = "Static Interfaces in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"We present an extensible framework for defining and
|
||||
using ``static interfaces'' in C++. Static interfaces are especially
|
||||
useful as constraints on template parameters. That is, in addition to the
|
||||
usual template $class T$, template definitions can specify that T ``isa''
|
||||
Foo, for some static interface named Foo. These ``isa-constraints'' can be
|
||||
based on either inheritance (named conformance: T publicly inherits Foo),
|
||||
members (structural conformance: T has these member functions with these
|
||||
signatures), or both. The constraint mechanism imposes no space or time
|
||||
overheads at runtime; virtual functions are conspicuously absent from
|
||||
our framework.
|
||||
|
||||
We demonstrate two key utilities of static interfaces. First,
|
||||
constraints enable better error messages with template code. By applying
|
||||
static interfaces as constraints, instantiating a template with the
|
||||
wrong type is an error that can be caught at the instantiation point,
|
||||
rather than later (typically in the bowels of the implementation).
|
||||
Authors of template classes and template functions can also dispatch
|
||||
``custom error messages'' to report named constraint violations by
|
||||
clients, making debugging easier. We show examples of the improvement of
|
||||
error messages when constraints are applied to STL code.
|
||||
|
||||
Second, constraints enable automatic compile-time dispatch of different
|
||||
implementations of class or function templates based on the named
|
||||
conformance properties of the template types. For example, $Set<T>$ can be
|
||||
written to automatically choose the most efficient implementation: use a
|
||||
hashtable implementation if ``T isa Hashable'', or else a binary search
|
||||
tree if ``T isa LessThanComparable'' , or else a linked-list if merely ``T
|
||||
isa EqualityComparable''. This dispatch can be completely hidden from
|
||||
clients of Set, who just use $Set<T>$ as usual."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Siek,
|
||||
AUTHOR = "Jeremy Siek and Andrew Lumsdaine",
|
||||
TITLE = "Concept Checking: Binding Parametric Polymorphism in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Generic programming in C++ is characterized by the use of template
|
||||
parameters to represent abstract data types (or ``concepts'').
|
||||
However, the C++ language itself does not provide a mechanism for
|
||||
explicitly handling concepts. As a result, it can be difficult to
|
||||
insure that a concrete type meets the requirements of the concept it
|
||||
is supposed to represent. Error messages resulting from incorrect
|
||||
use of a concrete type can be particularly difficult to decipher.
|
||||
In this paper we present techniques to check parameters in generic
|
||||
C++ libraries. Our techniques use standard C++ and introduce no
|
||||
run-time overhead."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Kuehl,
|
||||
AUTHOR = "Dietmar K{\"u}hl",
|
||||
TITLE = "{STL} and {OO} Don't Easily Mix",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"The STL is a powerful tool for many kinds of processing. Unfortunately,
|
||||
using polymorphic objects with the STL seems not to work: Polymorphic
|
||||
objects stored in STL containers either get sliced (i.e. only the base
|
||||
part is copied or assigned but not the derived part) or, when storing
|
||||
pointers to them instead, are not destroyed. Applying algorithms to
|
||||
such containers often results in the wrong thing or complex predicate
|
||||
objects are needed. This article shows how to overcome at least some
|
||||
of these problems using some adaptors and also outlines a possible
|
||||
implementation of STL for better integration with polymorphic objects.
|
||||
The improved integration just acknowledges the distinction between the
|
||||
object and the entity used to maintain it."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Eichelberger,
|
||||
AUTHOR = "H. Eichelberger and J. Wolff v. Gudenberg",
|
||||
TITLE = "{UML} Description of the {STL}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/eichelberger.pdf",
|
||||
ABSTRACT =
|
||||
"In this paper we show how the specification of the
|
||||
Standard Template Library STL and its implementation can be described
|
||||
by UML diagrams. We define appropriate stereotypes to
|
||||
describe STL concepts like containers, iterators, function
|
||||
objects and global algorithms. For the graphical description of the
|
||||
implementation of the STL we extend the UML metamodel."
|
||||
}
|
||||
|
223
transform_iterator.htm
Normal file
223
transform_iterator.htm
Normal file
@@ -0,0 +1,223 @@
|
||||
<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>Transform Iterator Adaptor 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>Transform Iterator Adaptor</h1>
|
||||
|
||||
Defined in header
|
||||
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
<p>
|
||||
The transform iterator adaptor augments an iterator by applying some
|
||||
function object to the result of dereferencing the iterator. Another
|
||||
words, the <tt>operator*</tt> of the transform iterator first
|
||||
dereferences the base iterator, passes the result of this to the
|
||||
function object, and then returns the result. The following
|
||||
<b>pseudo-code</b> shows the basic idea:
|
||||
|
||||
<pre>
|
||||
value_type transform_iterator::operator*() const {
|
||||
return this->f(*this->base_iterator);
|
||||
}
|
||||
</pre>
|
||||
|
||||
All of the other operators of the transform iterator behave in the
|
||||
same fashion as those of the base iterator.
|
||||
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
class transform_iterator_generator;
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
typename transform_iterator_generator<AdaptableUnaryFunction,Iterator>::type
|
||||
make_transform_iterator(BaseIterator base, const AdaptableUnaryFunction& f = AdaptableUnaryFunction());
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="transform_iterator_generator">The Transform Iterator Type
|
||||
Generator</a></h2>
|
||||
|
||||
The class <tt>transform_iterator_generator</tt> is a helper class whose
|
||||
purpose is to construct a transform iterator type. The template
|
||||
parameters for this class are the <tt>AdaptableUnaryFunction</tt> function object
|
||||
type and the <tt>BaseIterator</tt> type that is being wrapped.
|
||||
|
||||
<pre>
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
class transform_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...> type;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
<p>
|
||||
The following is an example of how to use the
|
||||
<tt>transform_iterator_generator</tt> class to iterate through a range
|
||||
of numbers, multiplying each of them by 2 when they are dereferenced.
|
||||
The <tt>boost::binder1st</tt> class is used instead of the standard
|
||||
one because tranform iterator requires the function object to be
|
||||
Default Constructible.
|
||||
|
||||
<p>
|
||||
<PRE>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
// definition of class boost::binder1st and function boost::bind1st() ...
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
typedef boost::binder1st< std::multiplies<int> > Function;
|
||||
typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator;
|
||||
|
||||
doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)),
|
||||
i_end(x + sizeof(x)/sizeof(int), boost::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;
|
||||
|
||||
// to be continued...
|
||||
</PRE>
|
||||
The output from this part is:
|
||||
<pre>
|
||||
2 4 6 8 10 12 14 16
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a
|
||||
href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
|
||||
<TD>The function object that transforms each element in the iterator
|
||||
range. The <tt>argument_type</tt> of the function object must match
|
||||
the value type of the base iterator. The <tt>result_type</tt> of the
|
||||
function object will be the resulting iterator's
|
||||
<tt>value_type</tt>. If you want the resulting iterator to behave as
|
||||
an iterator, the result of the function should be solely a function of
|
||||
its argument. Also, the function object must be <a
|
||||
href="http://www.sgi.com/tech/stl/DefaultConstructible.html"> Default
|
||||
Constructible</a> (which many of the standard function objects are not).</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The iterator type being wrapped. This type must at least be a model
|
||||
of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
The transform iterator adaptor (the type
|
||||
<tt>transform_iterator_generator<...>::type</tt>) is a model of <a
|
||||
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a><a href="#1">[1]</a>.
|
||||
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The transform iterator type implements the member functions and
|
||||
operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a>
|
||||
concept, except that the <tt>reference</tt> type is the same as the <tt>value_type</tt>
|
||||
so <tt>operator*()</tt> returns by-value. In addition it has the following constructor:
|
||||
|
||||
<pre>
|
||||
transform_iterator_generator::type(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
|
||||
<h2><a name="make_transform_iterator">The Transform Iterator Object Generator</a></h2>
|
||||
|
||||
<pre>
|
||||
template <class AdaptableUnaryFunction, class BaseIterator>
|
||||
typename transform_iterator_generator<AdaptableUnaryFunction,BaseIterator>::type
|
||||
make_transform_iterator(BaseIterator base,
|
||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction());
|
||||
</pre>
|
||||
|
||||
This function provides a convenient way to create transform iterators.
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
Continuing from the previous example, we use the <tt>make_transform_iterator()</tt>
|
||||
function to add four to each element of the array.
|
||||
|
||||
<pre>
|
||||
std::cout << "adding 4 to each element in the array:" << std::endl;
|
||||
|
||||
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
|
||||
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
The output from this part is:
|
||||
<pre>
|
||||
5 6 7 8 9 10 11 12
|
||||
</pre>
|
||||
|
||||
<h3>Notes</h3>
|
||||
|
||||
|
||||
<a name="1">[1]</a> If the base iterator is a model of <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a>
|
||||
then the transform iterator will also suppport most of the
|
||||
functionality required by the Random Access Iterator concept. However, a
|
||||
transform iterator can never completely satisfy the requirements for
|
||||
<a
|
||||
href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward Iterator</a>
|
||||
(or of any concepts that refine Forward Iterator, which includes
|
||||
Random Access Iterator and Bidirectional Iterator) since the <tt>operator*</tt> of the transform
|
||||
iterator always returns by-value.
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->29 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14896" --></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>
|
76
transform_iterator_example.cpp
Normal file
76
transform_iterator_example.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// (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/iterator_adaptors.hpp>
|
||||
|
||||
// What a bummer. We can't use std::binder1st with transform iterator
|
||||
// because it does not have a default constructor. Here's a version
|
||||
// that does.
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <class Operation>
|
||||
class binder1st
|
||||
: public std::unary_function<typename Operation::second_argument_type,
|
||||
typename Operation::result_type> {
|
||||
protected:
|
||||
Operation op;
|
||||
typename Operation::first_argument_type value;
|
||||
public:
|
||||
binder1st() { } // this had to be added!
|
||||
binder1st(const Operation& x,
|
||||
const typename Operation::first_argument_type& y)
|
||||
: op(x), value(y) {}
|
||||
typename Operation::result_type
|
||||
operator()(const typename Operation::second_argument_type& x) const {
|
||||
return op(value, x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Operation, class T>
|
||||
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
|
||||
typedef typename Operation::first_argument_type arg1_type;
|
||||
return binder1st<Operation>(op, arg1_type(x));
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
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 };
|
||||
const int N = sizeof(x)/sizeof(int);
|
||||
|
||||
typedef boost::binder1st< std::multiplies<int> > Function;
|
||||
typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator;
|
||||
|
||||
doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)),
|
||||
i_end(x + N, boost::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;
|
||||
|
||||
std::cout << "adding 4 to each element in the array:" << std::endl;
|
||||
|
||||
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
|
||||
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
54
transform_iterator_test.cpp
Normal file
54
transform_iterator_test.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// (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.
|
||||
|
||||
// Revision History
|
||||
// 08 Mar 2001 Jeremy Siek
|
||||
// Moved test of transform iterator into its own file. It to
|
||||
// to be in iterator_adaptor_test.cpp.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <boost/pending/iterator_tests.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
const int N = 10;
|
||||
|
||||
// Borland is getting confused about typedef's and constructors here
|
||||
|
||||
// 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_generator<mult_functor, int*>::type i(y, mult_functor(2));
|
||||
boost::input_iterator_test(i, x[0], x[1]);
|
||||
boost::input_iterator_test(boost::make_transform_iterator(&y[0], mult_functor(2)), x[0], x[1]);
|
||||
}
|
||||
std::cout << "test successful " << std::endl;
|
||||
return 0;
|
||||
}
|
@@ -1,534 +0,0 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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.
|
||||
|
||||
/* Release notes:
|
||||
23rd July 2000:
|
||||
Removed all call_traits tests to call_traits_test.cpp
|
||||
Removed all compressed_pair tests to compressed_pair_tests.cpp
|
||||
Improved tests macros
|
||||
Tidied up specialistions of type_types classes for test cases.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
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;}
|
||||
#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:
|
||||
// is_enum for all enumerations (is_enum implies is_POD)
|
||||
// is_union for all unions
|
||||
// is_empty for all empty composites
|
||||
// is_POD for all PODs (except enums) (is_POD implies has_*)
|
||||
// has_* for any UDT that has that trait and is not POD
|
||||
|
||||
enum enum_UDT{ one, two, three };
|
||||
struct UDT
|
||||
{
|
||||
UDT();
|
||||
~UDT();
|
||||
UDT(const UDT&);
|
||||
UDT& operator=(const UDT&);
|
||||
int i;
|
||||
|
||||
void f1();
|
||||
int f2();
|
||||
int f3(int);
|
||||
int f4(int, float);
|
||||
};
|
||||
|
||||
struct POD_UDT { int x; };
|
||||
struct empty_UDT{ ~empty_UDT(){}; };
|
||||
struct empty_POD_UDT{};
|
||||
union union_UDT
|
||||
{
|
||||
int x;
|
||||
double y;
|
||||
~union_UDT();
|
||||
};
|
||||
union POD_union_UDT
|
||||
{
|
||||
int x;
|
||||
double y;
|
||||
};
|
||||
union empty_union_UDT
|
||||
{
|
||||
~empty_union_UDT();
|
||||
};
|
||||
union empty_POD_union_UDT{};
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
namespace boost {
|
||||
template <> struct is_enum<enum_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_POD<POD_UDT>
|
||||
{ static const bool value = true; };
|
||||
// this type is not POD, so we have to specialize the has_* individually
|
||||
template <> struct has_trivial_constructor<empty_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct has_trivial_copy<empty_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct has_trivial_assign<empty_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_POD<empty_POD_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_union<union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_union<POD_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_POD<POD_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_union<empty_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
// this type is not POD, so we have to specialize the has_* individually
|
||||
template <> struct has_trivial_constructor<empty_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct has_trivial_copy<empty_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct has_trivial_assign<empty_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_union<empty_POD_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_POD<empty_POD_union_UDT>
|
||||
{ static const bool value = true; };
|
||||
}
|
||||
#else
|
||||
namespace boost {
|
||||
template <> struct is_enum<enum_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_POD<POD_UDT>
|
||||
{ enum{ value = true }; };
|
||||
// this type is not POD, so we have to specialize the has_* individually
|
||||
template <> struct has_trivial_constructor<empty_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct has_trivial_copy<empty_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct has_trivial_assign<empty_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_POD<empty_POD_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_union<union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_union<POD_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_POD<POD_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_union<empty_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
// this type is not POD, so we have to specialize the has_* individually
|
||||
template <> struct has_trivial_constructor<empty_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct has_trivial_copy<empty_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct has_trivial_assign<empty_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_union<empty_POD_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_POD<empty_POD_union_UDT>
|
||||
{ enum{ value = true }; };
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// not considering cv-qual's as a part of the type -- they are considered
|
||||
// compiler hints only. These failures should be fixed before long.
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Checking type operations..." << std::endl << std::endl;
|
||||
|
||||
// cv-qualifiers applied to reference types should have no effect
|
||||
// declare these here for later use with is_reference and remove_reference:
|
||||
typedef int& r_type;
|
||||
typedef const r_type cr_type;
|
||||
|
||||
type_test(int, remove_reference<int>::type)
|
||||
type_test(const int, remove_reference<const int>::type)
|
||||
type_test(int, remove_reference<int&>::type)
|
||||
type_test(const int, remove_reference<const int&>::type)
|
||||
type_test(volatile int, remove_reference<volatile int&>::type)
|
||||
type_test(int, remove_reference<cr_type>::type)
|
||||
|
||||
type_test(int, remove_const<const int>::type)
|
||||
// Steve: fails on BCB4
|
||||
type_test(volatile int, remove_const<volatile int>::type)
|
||||
// Steve: fails on BCB4
|
||||
type_test(volatile int, remove_const<const volatile int>::type)
|
||||
type_test(int, remove_const<int>::type)
|
||||
type_test(int*, remove_const<int* const>::type)
|
||||
type_test(int, remove_volatile<volatile int>::type)
|
||||
// Steve: fails on BCB4
|
||||
type_test(const int, remove_volatile<const int>::type)
|
||||
// Steve: fails on BCB4
|
||||
type_test(const int, remove_volatile<const volatile int>::type)
|
||||
type_test(int, remove_volatile<int>::type)
|
||||
type_test(int*, remove_volatile<int* volatile>::type)
|
||||
type_test(int, remove_cv<volatile int>::type)
|
||||
type_test(int, remove_cv<const int>::type)
|
||||
type_test(int, remove_cv<const volatile int>::type)
|
||||
type_test(int, remove_cv<int>::type)
|
||||
type_test(int*, remove_cv<int* volatile>::type)
|
||||
type_test(int*, remove_cv<int* const>::type)
|
||||
type_test(int*, remove_cv<int* const volatile>::type)
|
||||
type_test(const int *, remove_cv<const int * const>::type)
|
||||
type_test(int, remove_bounds<int>::type)
|
||||
type_test(int*, remove_bounds<int*>::type)
|
||||
type_test(int, remove_bounds<int[3]>::type)
|
||||
type_test(int[3], remove_bounds<int[2][3]>::type)
|
||||
|
||||
std::cout << std::endl << "Checking type properties..." << std::endl << std::endl;
|
||||
|
||||
value_test(true, (is_same<int, int>::value))
|
||||
value_test(false, (is_same<int, const int>::value))
|
||||
value_test(false, (is_same<int, 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[2]>::value))
|
||||
|
||||
value_test(false, is_const<int>::value)
|
||||
value_test(true, is_const<const int>::value)
|
||||
value_test(false, is_const<volatile int>::value)
|
||||
value_test(true, is_const<const volatile int>::value)
|
||||
|
||||
value_test(false, is_volatile<int>::value)
|
||||
value_test(false, is_volatile<const int>::value)
|
||||
value_test(true, is_volatile<volatile int>::value)
|
||||
value_test(true, is_volatile<const volatile int>::value)
|
||||
|
||||
value_test(true, is_void<void>::value)
|
||||
// Steve: fails on BCB4
|
||||
// JM: but looks as though it should according to [3.9.3p1]?
|
||||
//value_test(false, is_void<const void>::value)
|
||||
value_test(false, is_void<int>::value)
|
||||
|
||||
value_test(false, is_standard_unsigned_integral<UDT>::value)
|
||||
value_test(false, is_standard_unsigned_integral<void>::value)
|
||||
value_test(false, is_standard_unsigned_integral<bool>::value)
|
||||
value_test(false, is_standard_unsigned_integral<char>::value)
|
||||
value_test(false, is_standard_unsigned_integral<signed char>::value)
|
||||
value_test(true, is_standard_unsigned_integral<unsigned char>::value)
|
||||
value_test(false, is_standard_unsigned_integral<wchar_t>::value)
|
||||
value_test(false, is_standard_unsigned_integral<short>::value)
|
||||
value_test(true, is_standard_unsigned_integral<unsigned short>::value)
|
||||
value_test(false, is_standard_unsigned_integral<int>::value)
|
||||
value_test(true, is_standard_unsigned_integral<unsigned int>::value)
|
||||
value_test(false, is_standard_unsigned_integral<long>::value)
|
||||
value_test(true, is_standard_unsigned_integral<unsigned long>::value)
|
||||
value_test(false, is_standard_unsigned_integral<float>::value)
|
||||
value_test(false, is_standard_unsigned_integral<double>::value)
|
||||
value_test(false, is_standard_unsigned_integral<long double>::value)
|
||||
#ifdef ULLONG_MAX
|
||||
value_test(false, is_standard_unsigned_integral<long long>::value)
|
||||
value_test(false, is_standard_unsigned_integral<unsigned long long>::value)
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
value_test(false, is_standard_unsigned_integral<__int64>::value)
|
||||
value_test(false, is_standard_unsigned_integral<unsigned __int64>::value)
|
||||
#endif
|
||||
|
||||
value_test(false, is_standard_signed_integral<UDT>::value)
|
||||
value_test(false, is_standard_signed_integral<void>::value)
|
||||
value_test(false, is_standard_signed_integral<bool>::value)
|
||||
value_test(false, is_standard_signed_integral<char>::value)
|
||||
value_test(true, is_standard_signed_integral<signed char>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned char>::value)
|
||||
value_test(false, is_standard_signed_integral<wchar_t>::value)
|
||||
value_test(true, is_standard_signed_integral<short>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned short>::value)
|
||||
value_test(true, is_standard_signed_integral<int>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned int>::value)
|
||||
value_test(true, is_standard_signed_integral<long>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned long>::value)
|
||||
value_test(false, is_standard_signed_integral<float>::value)
|
||||
value_test(false, is_standard_signed_integral<double>::value)
|
||||
value_test(false, is_standard_signed_integral<long double>::value)
|
||||
#ifdef ULLONG_MAX
|
||||
value_test(false, is_standard_signed_integral<long long>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned long long>::value)
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
value_test(false, is_standard_signed_integral<__int64>::value)
|
||||
value_test(false, is_standard_signed_integral<unsigned __int64>::value)
|
||||
#endif
|
||||
|
||||
value_test(false, is_standard_arithmetic<UDT>::value)
|
||||
value_test(false, is_standard_arithmetic<void>::value)
|
||||
value_test(true, is_standard_arithmetic<bool>::value)
|
||||
value_test(true, is_standard_arithmetic<char>::value)
|
||||
value_test(true, is_standard_arithmetic<signed char>::value)
|
||||
value_test(true, is_standard_arithmetic<unsigned char>::value)
|
||||
value_test(true, is_standard_arithmetic<wchar_t>::value)
|
||||
value_test(true, is_standard_arithmetic<short>::value)
|
||||
value_test(true, is_standard_arithmetic<unsigned short>::value)
|
||||
value_test(true, is_standard_arithmetic<int>::value)
|
||||
value_test(true, is_standard_arithmetic<unsigned int>::value)
|
||||
value_test(true, is_standard_arithmetic<long>::value)
|
||||
value_test(true, is_standard_arithmetic<unsigned long>::value)
|
||||
value_test(true, is_standard_arithmetic<float>::value)
|
||||
value_test(true, is_standard_arithmetic<double>::value)
|
||||
value_test(true, is_standard_arithmetic<long double>::value)
|
||||
#ifdef ULLONG_MAX
|
||||
value_test(false, is_standard_arithmetic<long long>::value)
|
||||
value_test(false, is_standard_arithmetic<unsigned long long>::value)
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
value_test(false, is_standard_arithmetic<__int64>::value)
|
||||
value_test(false, is_standard_arithmetic<unsigned __int64>::value)
|
||||
#endif
|
||||
|
||||
value_test(false, is_standard_fundamental<UDT>::value)
|
||||
value_test(true, is_standard_fundamental<void>::value)
|
||||
value_test(true, is_standard_fundamental<bool>::value)
|
||||
value_test(true, is_standard_fundamental<char>::value)
|
||||
value_test(true, is_standard_fundamental<signed char>::value)
|
||||
value_test(true, is_standard_fundamental<unsigned char>::value)
|
||||
value_test(true, is_standard_fundamental<wchar_t>::value)
|
||||
value_test(true, is_standard_fundamental<short>::value)
|
||||
value_test(true, is_standard_fundamental<unsigned short>::value)
|
||||
value_test(true, is_standard_fundamental<int>::value)
|
||||
value_test(true, is_standard_fundamental<unsigned int>::value)
|
||||
value_test(true, is_standard_fundamental<long>::value)
|
||||
value_test(true, is_standard_fundamental<unsigned long>::value)
|
||||
value_test(true, is_standard_fundamental<float>::value)
|
||||
value_test(true, is_standard_fundamental<double>::value)
|
||||
value_test(true, is_standard_fundamental<long double>::value)
|
||||
#ifdef ULLONG_MAX
|
||||
value_test(false, is_standard_fundamental<long long>::value)
|
||||
value_test(false, is_standard_fundamental<unsigned long long>::value)
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
value_test(false, is_standard_fundamental<__int64>::value)
|
||||
value_test(false, is_standard_fundamental<unsigned __int64>::value)
|
||||
#endif
|
||||
|
||||
value_test(false, is_arithmetic<UDT>::value)
|
||||
value_test(true, is_arithmetic<char>::value)
|
||||
value_test(true, is_arithmetic<signed char>::value)
|
||||
value_test(true, is_arithmetic<unsigned char>::value)
|
||||
value_test(true, is_arithmetic<wchar_t>::value)
|
||||
value_test(true, is_arithmetic<short>::value)
|
||||
value_test(true, is_arithmetic<unsigned short>::value)
|
||||
value_test(true, is_arithmetic<int>::value)
|
||||
value_test(true, is_arithmetic<unsigned int>::value)
|
||||
value_test(true, is_arithmetic<long>::value)
|
||||
value_test(true, is_arithmetic<unsigned long>::value)
|
||||
value_test(true, is_arithmetic<float>::value)
|
||||
value_test(true, is_arithmetic<double>::value)
|
||||
value_test(true, is_arithmetic<long double>::value)
|
||||
value_test(true, is_arithmetic<bool>::value)
|
||||
#ifdef ULLONG_MAX
|
||||
value_test(true, is_arithmetic<long long>::value)
|
||||
value_test(true, is_arithmetic<unsigned long long>::value)
|
||||
#endif
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
value_test(true, is_arithmetic<__int64>::value)
|
||||
value_test(true, is_arithmetic<unsigned __int64>::value)
|
||||
#endif
|
||||
|
||||
value_test(false, is_array<int>::value)
|
||||
value_test(false, is_array<int*>::value)
|
||||
value_test(true, is_array<int[2]>::value)
|
||||
value_test(true, is_array<int[2][3]>::value)
|
||||
value_test(true, is_array<UDT[2]>::value)
|
||||
|
||||
typedef void(*f1)();
|
||||
typedef int(*f2)(int);
|
||||
typedef int(*f3)(int, bool);
|
||||
typedef void (UDT::*mf1)();
|
||||
typedef int (UDT::*mf2)();
|
||||
typedef int (UDT::*mf3)(int);
|
||||
typedef int (UDT::*mf4)(int, float);
|
||||
|
||||
value_test(false, is_pointer<int>::value)
|
||||
value_test(false, is_pointer<int&>::value)
|
||||
value_test(true, is_pointer<int*>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||
value_test(false, is_pointer<int*const>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||
value_test(false, is_pointer<int*volatile>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1
|
||||
value_test(false, is_pointer<int*const volatile>::value)
|
||||
value_test(true, is_pointer<f1>::value)
|
||||
value_test(true, is_pointer<f2>::value)
|
||||
value_test(true, is_pointer<f3>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3
|
||||
value_test(false, is_pointer<mf1>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3
|
||||
value_test(false, is_pointer<mf2>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3
|
||||
value_test(false, is_pointer<mf3>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9.2p3
|
||||
value_test(false, is_pointer<mf4>::value)
|
||||
|
||||
value_test(false, is_reference<bool>::value)
|
||||
value_test(true, is_reference<int&>::value)
|
||||
value_test(true, is_reference<const int&>::value)
|
||||
value_test(true, is_reference<volatile int &>::value)
|
||||
value_test(true, is_reference<r_type>::value)
|
||||
value_test(true, is_reference<cr_type>::value)
|
||||
|
||||
value_test(false, is_class<int>::value)
|
||||
value_test(false, is_class<const int>::value)
|
||||
value_test(false, is_class<volatile int>::value)
|
||||
value_test(false, is_class<int*>::value)
|
||||
value_test(false, is_class<int* const>::value)
|
||||
value_test(false, is_class<int[2]>::value)
|
||||
value_test(false, is_class<int&>::value)
|
||||
value_test(false, is_class<mf4>::value)
|
||||
value_test(false, is_class<f1>::value)
|
||||
value_test(false, is_class<enum_UDT>::value)
|
||||
value_test(true, is_class<UDT>::value)
|
||||
value_test(true, is_class<UDT const>::value)
|
||||
value_test(true, is_class<UDT volatile>::value)
|
||||
value_test(true, is_class<empty_UDT>::value)
|
||||
value_test(true, is_class<std::iostream>::value)
|
||||
value_test(false, is_class<UDT*>::value)
|
||||
value_test(false, is_class<UDT[2]>::value)
|
||||
value_test(false, is_class<UDT&>::value)
|
||||
|
||||
value_test(true, is_object<int>::value)
|
||||
value_test(true, is_object<UDT>::value)
|
||||
value_test(false, is_object<int&>::value)
|
||||
value_test(false, is_object<void>::value)
|
||||
value_test(true, is_standard_scalar<int>::value)
|
||||
value_test(true, is_extension_scalar<void*>::value)
|
||||
|
||||
value_test(false, is_enum<int>::value)
|
||||
value_test(true, is_enum<enum_UDT>::value)
|
||||
|
||||
value_test(false, is_member_pointer<f1>::value)
|
||||
value_test(false, is_member_pointer<f2>::value)
|
||||
value_test(false, is_member_pointer<f3>::value)
|
||||
value_test(true, is_member_pointer<mf1>::value)
|
||||
value_test(true, is_member_pointer<mf2>::value)
|
||||
value_test(true, is_member_pointer<mf3>::value)
|
||||
value_test(true, is_member_pointer<mf4>::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[2]>::value)
|
||||
value_test(false, is_empty<f1>::value)
|
||||
value_test(false, is_empty<mf1>::value)
|
||||
value_test(false, is_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_union_UDT>::value)
|
||||
value_test(false, is_empty<enum_UDT>::value)
|
||||
|
||||
value_test(true, has_trivial_constructor<int>::value)
|
||||
value_test(true, has_trivial_constructor<int*>::value)
|
||||
value_test(true, has_trivial_constructor<int*const>::value)
|
||||
value_test(true, has_trivial_constructor<const int>::value)
|
||||
value_test(true, has_trivial_constructor<volatile int>::value)
|
||||
value_test(true, has_trivial_constructor<int[2]>::value)
|
||||
value_test(true, has_trivial_constructor<int[3][2]>::value)
|
||||
value_test(true, has_trivial_constructor<int[2][4][5][6][3]>::value)
|
||||
value_test(true, has_trivial_constructor<f1>::value)
|
||||
value_test(true, has_trivial_constructor<mf2>::value)
|
||||
value_test(false, has_trivial_constructor<UDT>::value)
|
||||
value_test(true, has_trivial_constructor<empty_UDT>::value)
|
||||
value_test(true, has_trivial_constructor<enum_UDT>::value)
|
||||
|
||||
value_test(true, has_trivial_copy<int>::value)
|
||||
value_test(true, has_trivial_copy<int*>::value)
|
||||
value_test(true, has_trivial_copy<int*const>::value)
|
||||
value_test(true, has_trivial_copy<const int>::value)
|
||||
// Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10
|
||||
value_test(true, has_trivial_copy<volatile int>::value)
|
||||
value_test(true, has_trivial_copy<int[2]>::value)
|
||||
value_test(true, has_trivial_copy<int[3][2]>::value)
|
||||
value_test(true, has_trivial_copy<int[2][4][5][6][3]>::value)
|
||||
value_test(true, has_trivial_copy<f1>::value)
|
||||
value_test(true, has_trivial_copy<mf2>::value)
|
||||
value_test(false, has_trivial_copy<UDT>::value)
|
||||
value_test(true, has_trivial_copy<empty_UDT>::value)
|
||||
value_test(true, has_trivial_copy<enum_UDT>::value)
|
||||
|
||||
value_test(true, has_trivial_assign<int>::value)
|
||||
value_test(true, has_trivial_assign<int*>::value)
|
||||
value_test(true, has_trivial_assign<int*const>::value)
|
||||
value_test(true, has_trivial_assign<const int>::value)
|
||||
// Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10
|
||||
value_test(true, has_trivial_assign<volatile int>::value)
|
||||
value_test(true, has_trivial_assign<int[2]>::value)
|
||||
value_test(true, has_trivial_assign<int[3][2]>::value)
|
||||
value_test(true, has_trivial_assign<int[2][4][5][6][3]>::value)
|
||||
value_test(true, has_trivial_assign<f1>::value)
|
||||
value_test(true, has_trivial_assign<mf2>::value)
|
||||
value_test(false, has_trivial_assign<UDT>::value)
|
||||
value_test(true, has_trivial_assign<empty_UDT>::value)
|
||||
value_test(true, has_trivial_assign<enum_UDT>::value)
|
||||
|
||||
value_test(true, has_trivial_destructor<int>::value)
|
||||
value_test(true, has_trivial_destructor<int*>::value)
|
||||
value_test(true, has_trivial_destructor<int*const>::value)
|
||||
value_test(true, has_trivial_destructor<const int>::value)
|
||||
value_test(true, has_trivial_destructor<volatile int>::value)
|
||||
value_test(true, has_trivial_destructor<int[2]>::value)
|
||||
value_test(true, has_trivial_destructor<int[3][2]>::value)
|
||||
value_test(true, has_trivial_destructor<int[2][4][5][6][3]>::value)
|
||||
value_test(true, has_trivial_destructor<f1>::value)
|
||||
value_test(true, has_trivial_destructor<mf2>::value)
|
||||
value_test(false, has_trivial_destructor<UDT>::value)
|
||||
value_test(false, has_trivial_destructor<empty_UDT>::value)
|
||||
value_test(true, has_trivial_destructor<enum_UDT>::value)
|
||||
|
||||
value_test(true, is_POD<int>::value)
|
||||
value_test(true, is_POD<int*>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9p10
|
||||
value_test(false, is_POD<int&>::value)
|
||||
value_test(true, is_POD<int*const>::value)
|
||||
value_test(true, is_POD<const int>::value)
|
||||
// Steve: was 'false', should be 'true', via 3.9p10
|
||||
value_test(true, is_POD<volatile int>::value)
|
||||
// Steve: was 'true', should be 'false', via 3.9p10
|
||||
value_test(false, is_POD<const int&>::value)
|
||||
value_test(true, is_POD<int[2]>::value)
|
||||
value_test(true, is_POD<int[3][2]>::value)
|
||||
value_test(true, is_POD<int[2][4][5][6][3]>::value)
|
||||
value_test(true, is_POD<f1>::value)
|
||||
value_test(true, is_POD<mf2>::value)
|
||||
value_test(false, is_POD<UDT>::value)
|
||||
value_test(false, is_POD<empty_UDT>::value)
|
||||
value_test(true, is_POD<enum_UDT>::value)
|
||||
|
||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||
std::cin.get();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
146
utility.htm
Normal file
146
utility.htm
Normal file
@@ -0,0 +1,146 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Header boost/utility.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/utility.hpp">boost/utility.hpp</a></h1>
|
||||
|
||||
<p>The entire contents of the header <code><a href="../../boost/utility.hpp"><boost/utility.hpp></a></code>
|
||||
are in <code>namespace boost</code>.</p>
|
||||
|
||||
<h2>Contents</h2>
|
||||
|
||||
<ul>
|
||||
<li>Function templates <a href="#checked_delete">checked_delete() and
|
||||
checked_array_delete()</a></li>
|
||||
<li>Function templates <a href="#functions next">next() and prior()</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>
|
||||
<h2> Function templates <a name="checked_delete">checked_delete</a>() and
|
||||
checked_array_delete()</h2>
|
||||
|
||||
<p>Deletion of a pointer to an incomplete type is an unsafe programming practice
|
||||
because there is no way for the compiler to verify that the destructor is indeed
|
||||
trivial. The checked_delete() and checked_array_delete() function
|
||||
templates simply <b>delete</b> or <b>delete[]</b> their argument, but also
|
||||
require that their argument be a complete type. They issue an appropriate
|
||||
compiler error diagnostic if that requirement is not met. A typical
|
||||
implementation is shown; other implementations may vary:</p>
|
||||
|
||||
<pre> template< typename T >
|
||||
inline void checked_delete(T const volatile * x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point
|
||||
// of instantiation
|
||||
delete x;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline void checked_array_delete(T const volatile * x)
|
||||
{
|
||||
BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point
|
||||
// of instantiation
|
||||
delete [] x;
|
||||
}</pre>
|
||||
|
||||
<p>Contributed by Beman Dawes, based on a suggestion from Dave Abrahams,
|
||||
generalizing an idea from Vladimir Prus, with comments from Rainer Deyke, John
|
||||
Maddock, and others.</p>
|
||||
|
||||
<h3>Background</h3>
|
||||
|
||||
<p>The C++ Standard specifies that delete on a pointer to an incomplete types is
|
||||
undefined behavior if the type has a non-trivial destructor in [expr.delete]
|
||||
5.3.5 paragraph. No diagnostic is required. Some but not all
|
||||
compilers issue warnings if the type is incomplete at point of deletion.</p>
|
||||
|
||||
<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
|
||||
bidirectional iterators, do not provide addition and subtraction via operator+()
|
||||
or operator-(). This means that non-modifying computation of the next or
|
||||
prior value requires a temporary, even though operator++() or operator--() is
|
||||
provided. It also means that writing code like <code>itr+1</code> inside a
|
||||
template restricts the iterator category to random access iterators.</p>
|
||||
|
||||
<p>The next() and prior() functions provide a simple way around these problems:</p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<pre>template <class T>
|
||||
T next(T x) { return ++x; }
|
||||
|
||||
template <class X>
|
||||
T prior(T x) { return --x; }</pre>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p>Usage is simple:</p>
|
||||
|
||||
<blockquote>
|
||||
|
||||
<pre>const std::list<T>::iterator p = get_some_iterator();
|
||||
const std::list<T>::iterator prev = boost::prior(p);</pre>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<p>Contributed by <a href="../../people/dave_abrahams.htm">Dave Abrahams</a>.</p>
|
||||
|
||||
<h2><a name="Class noncopyable">Class noncopyable</a></h2>
|
||||
|
||||
<p>Class <strong>noncopyable</strong> is a base class. Derive your own class from <strong>noncopyable</strong>
|
||||
when you want to prohibit copy construction and copy assignment.</p>
|
||||
|
||||
<p>Some objects, particularly those which hold complex resources like files or
|
||||
network connections, have no sensible copy semantics. Sometimes there are
|
||||
possible copy semantics, but these would be of very limited usefulness and be
|
||||
very difficult to implement correctly. Sometimes you're implementing a class that doesn't need to be copied
|
||||
just yet and you don't want to take the time to write the appropriate functions.
|
||||
Deriving from <b> noncopyable</b> will prevent the otherwise implicitly-generated
|
||||
functions (which don't have the proper semantics) from becoming a trap for other programmers.</p>
|
||||
|
||||
<p>The traditional way to deal with these is to declare a private copy constructor and copy assignment, and then
|
||||
document why this is done. But deriving from <b>noncopyable</b> is simpler
|
||||
and clearer, and doesn't require additional documentation.</p>
|
||||
|
||||
<p>The program <a href="noncopyable_test.cpp">noncopyable_test.cpp</a> can be
|
||||
used to verify class <b>noncopyable</b> works as expected. It has have been run successfully under
|
||||
GCC 2.95, Metrowerks
|
||||
CodeWarrior 5.0, and Microsoft Visual C++ 6.0 sp 3.</p>
|
||||
|
||||
<p>Contributed by <a href="../../people/dave_abrahams.htm">Dave Abrahams</a>.</p>
|
||||
|
||||
<h3>Example</h3>
|
||||
<blockquote>
|
||||
<pre>// inside one of your own headers ...
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
class ResourceLadenFileSystem : boost::noncopyable {
|
||||
...</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Rationale</h3>
|
||||
<p>Class noncopyable has protected constructor and destructor members to
|
||||
emphasize that it is to be used only as a base class. Dave Abrahams notes
|
||||
concern about the effect on compiler optimization of adding (even trivial inline)
|
||||
destructor declarations. He says "Probably this concern is misplaced, because
|
||||
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p>
|
||||
<h2>Function template tie()</h2>
|
||||
<p>See <a href="tie.html">separate documentation</a>.</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
|
||||
-->22 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13960"
|
||||
-->
|
||||
</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>
|
Reference in New Issue
Block a user