mirror of
https://github.com/boostorg/utility.git
synced 2025-06-25 12:01:38 +02:00
Compare commits
515 Commits
boost-1.18
...
svn-branch
Author | SHA1 | Date | |
---|---|---|---|
bf2154d563 | |||
f66e844ff1 | |||
62e8cc2b36 | |||
30236f8915 | |||
155e787ea3 | |||
1d60d49136 | |||
2dffdac9fe | |||
ddf00eb29d | |||
0a6acd8ce8 | |||
745322e797 | |||
9f10fc03ce | |||
84fbb3c896 | |||
865c707756 | |||
871f3a6779 | |||
aaca5ca871 | |||
5a4e19989f | |||
6ea398c446 | |||
1bd83d43e8 | |||
5ca5b4102b | |||
aca7699046 | |||
e702a944ca | |||
a157c345ee | |||
dcb2dd4736 | |||
ae19cd6236 | |||
3ab4d38931 | |||
18c7fb72b5 | |||
6bb092a9b1 | |||
f721b8b28c | |||
e5ba34472d | |||
082ae17eaf | |||
dd86e09ab4 | |||
baff23116e | |||
e549baf93a | |||
30d46adcb7 | |||
e854726be0 | |||
d198bd9d96 | |||
5eb23cecd0 | |||
eff2c75bba | |||
325bd73df7 | |||
0fcc554abd | |||
b685784155 | |||
ac90fdc611 | |||
51077e49f5 | |||
0c3199f72d | |||
62675a3bcd | |||
c26dbaa620 | |||
8201624959 | |||
f2116413d6 | |||
b0baebeb0a | |||
fb943b77d5 | |||
b4b39510fc | |||
6f0f05ba12 | |||
f0b64b6229 | |||
4229488989 | |||
acd2e6ef2b | |||
c26aaed71f | |||
326d7ad4d7 | |||
c76a2f4aab | |||
d8b0ff2d7e | |||
996ce2d307 | |||
167fa4154f | |||
0c7e7c3c39 | |||
9d8f8f41dc | |||
39c4445b39 | |||
7819b022ad | |||
65d27e7f86 | |||
212a70bf77 | |||
6b5dc18a46 | |||
0917f83b9c | |||
7322bd3903 | |||
e998010184 | |||
918a1c93e4 | |||
14c87853c2 | |||
d5a5b84a40 | |||
35d3c03d19 | |||
8933fbb254 | |||
c320330cd5 | |||
822b46a3df | |||
a821ef6e2c | |||
491db15997 | |||
b6c826a139 | |||
7b472a05ee | |||
9a07bc0d9b | |||
154d6bb198 | |||
0dde936e61 | |||
918bf25039 | |||
04fda4fb4e | |||
e14a250d6e | |||
806745f24e | |||
4231f774e4 | |||
dfc320124f | |||
be43ba1569 | |||
f3f879555a | |||
3155044abd | |||
484d184de5 | |||
3305cf1592 | |||
ec36cd8c54 | |||
61fb5a0b8f | |||
8024c3e9c7 | |||
2f5945d0cd | |||
929517d6d7 | |||
abcab174a5 | |||
801be90699 | |||
265c2348b8 | |||
fb95bcc64c | |||
aedc410525 | |||
7fa440c154 | |||
746e0fad2b | |||
1616f6f5a8 | |||
ca3e7d8530 | |||
f0f753ba6c | |||
532065b51b | |||
4bfb534bae | |||
95ba7a4381 | |||
e92213431e | |||
7dd7daee1b | |||
953cc46220 | |||
b5ae0ad86b | |||
c86fcbf456 | |||
6ded8b9ad6 | |||
bb6a6272e1 | |||
242634b3fc | |||
662cf14bf6 | |||
fe3aaf62cd | |||
cb189bd6be | |||
f57c914b8f | |||
7cec198e14 | |||
52d3120528 | |||
f1aff5670c | |||
632f682292 | |||
d1d0d6b788 | |||
3bd833c8ff | |||
1ef77b0853 | |||
074007ab8c | |||
c4b7aaf281 | |||
22b8494e9a | |||
c1c8329403 | |||
20a89040e1 | |||
1c7a2a1476 | |||
7c40cc0b63 | |||
73a9e0d351 | |||
dc9856744a | |||
88f4e47550 | |||
1be04eeec5 | |||
56acf9c325 | |||
c6e3957efc | |||
25e8284950 | |||
37a6537a5b | |||
80df1d8f12 | |||
75afed7f17 | |||
1d7066aee1 | |||
12272a38d4 | |||
04f901e52e | |||
fabfb31bf6 | |||
683701cd07 | |||
119c64be0b | |||
d429c9a7d8 | |||
1e8216431b | |||
e45b2e2136 | |||
9e6951009b | |||
a009a209f1 | |||
97605056ed | |||
8fcfa33d33 | |||
aa65e3da3b | |||
b4cfadb4d5 | |||
45a6249668 | |||
1d601aef4d | |||
32fb45eba9 | |||
2b7d10aceb | |||
5dc62711e1 | |||
252c02aca0 | |||
9655beb7ba | |||
f0ea53e77e | |||
4755b42909 | |||
ef9af03c6c | |||
7439073cbf | |||
aff985a563 | |||
db425222d5 | |||
e20af510f7 | |||
d8230c6a73 | |||
f5690787bf | |||
a4fd7b32dd | |||
f4336ec693 | |||
03d906976b | |||
4ba6a96822 | |||
1ea4140d56 | |||
351d4ecb15 | |||
7fbf84dcc6 | |||
3ff49b272d | |||
5b52e3d418 | |||
8c0eb498d3 | |||
48a81ef7ea | |||
f7610c9b26 | |||
1755eaf019 | |||
6b8b218efb | |||
333d79b345 | |||
f0fa436fe4 | |||
13e6d78fa8 | |||
7126ea2685 | |||
a37518cb4a | |||
64b3e8c3bd | |||
339937380e | |||
6156f0d302 | |||
00560e8e17 | |||
029ff9828f | |||
ec188c7c3e | |||
0a0296a5d0 | |||
6e26a5bbe7 | |||
dc1b6246a0 | |||
15f69eaf14 | |||
4774a0d325 | |||
be78ab72c9 | |||
0bc4a1b20d | |||
c8b674d105 | |||
b421d4725a | |||
1662bb5713 | |||
ad79a21abd | |||
19645a52e6 | |||
74c3077c9a | |||
1f29191329 | |||
4b636a7680 | |||
e6fc2555f3 | |||
e27d0fcf2a | |||
2643c33b20 | |||
71af1e77c8 | |||
99e7406bd9 | |||
413265f497 | |||
fe44cdf09b | |||
e413428d71 | |||
88b9822db7 | |||
24045c0cd7 | |||
d2aa9f4a84 | |||
d2a5fd169f | |||
4e350d9934 | |||
f3f697bbc8 | |||
c7c09696db | |||
dbcc58d984 | |||
8231310c4d | |||
2988140430 | |||
7387966005 | |||
e0a5a61375 | |||
66ecd70689 | |||
67f4f45653 | |||
1bf28b3de2 | |||
eb3c3435d7 | |||
8a81d8b16c | |||
bc9d8b13d0 | |||
4768b167ab | |||
591ff70ed1 | |||
7bf2ad0b22 | |||
409c79b2e4 | |||
d0410691a1 | |||
64e5115138 | |||
7ae912d83c | |||
2937f5876c | |||
8619c9b5c3 | |||
e4d5684f6b | |||
3d69cf95da | |||
18944572b7 | |||
3e9d0f80c2 | |||
a2c4d1990a | |||
404261c6ee | |||
87abc59612 | |||
cb98ddf7db | |||
7d2e6c9025 | |||
75eaa14a18 | |||
082d6e3b32 | |||
35b3770b6f | |||
5b9d20c7e2 | |||
5bbed2372e | |||
a9d407d239 | |||
3ca4a33a65 | |||
95197f427c | |||
84cdfb032c | |||
ec2ceb9c96 | |||
6286c893fd | |||
354aef0e8c | |||
139e33c36d | |||
e01de59cdd | |||
686f822dea | |||
9961d5c9af | |||
628be0d125 | |||
633e45f61a | |||
2f357c3805 | |||
cda0894d0d | |||
117720a8bc | |||
a6f6c3613a | |||
7914f5b931 | |||
a1add0a6f6 | |||
c032b337c4 | |||
ec363261ae | |||
97cde2183d | |||
7f43c682db | |||
0c9eee3c6b | |||
3b1afa3ba6 | |||
93e6a75125 | |||
52f8a7c0ca | |||
55bfeb646f | |||
75c9dd3be1 | |||
6392e2788f | |||
6a97f3f9ba | |||
6e5f52e279 | |||
7f92bed902 | |||
d68a11cc42 | |||
328a81e194 | |||
31d0908b74 | |||
32c77599f4 | |||
812ebf3562 | |||
37f476013d | |||
9f3104166f | |||
64cc0daf34 | |||
d5d64df124 | |||
0edcfcd5c1 | |||
50ba2d419a | |||
ff3a77ca5a | |||
4eaed6c23d | |||
4d0dd46471 | |||
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 |
@ -1,188 +0,0 @@
|
||||
<HTML>
|
||||
<!--
|
||||
-- Copyright (c) Jeremy Siek 2000
|
||||
--
|
||||
-- Permission to use, copy, modify, distribute and sell this software
|
||||
-- and its documentation for any purpose is hereby granted without fee,
|
||||
-- provided that the above copyright notice appears in all copies and
|
||||
-- that both that copyright notice and this permission notice appear
|
||||
-- in supporting documentation. Silicon Graphics makes no
|
||||
-- representations about the suitability of this software for any
|
||||
-- purpose. It is provided "as is" without express or implied warranty.
|
||||
-->
|
||||
<Head>
|
||||
<Title>CopyConstructible</Title>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||
ALINK="#ff0000">
|
||||
<IMG SRC="../../c++boost.gif"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
<!--end header-->
|
||||
<BR Clear>
|
||||
<H1>CopyConstructible</H1>
|
||||
|
||||
<h3>Description</h3>
|
||||
A type is CopyConstructible if it is possible to copy objects of that
|
||||
type.
|
||||
|
||||
<h3>Notation</h3>
|
||||
<Table>
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
<tt>T</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
is type that is a model of CopyConstructible
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
<tt>t</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
is an object of type <tt>T</tt>
|
||||
</TD>
|
||||
</tr>
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
<tt>u</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
is an object of type <tt>const T</tt>
|
||||
</TD>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<h3>Definitions</h3>
|
||||
<h3>Valid expressions</h3>
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>
|
||||
Name
|
||||
</TH>
|
||||
<TH>
|
||||
Expression
|
||||
</TH>
|
||||
<TH>
|
||||
Return type
|
||||
</TH>
|
||||
<TH>
|
||||
Semantics
|
||||
</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
Copy constructor
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T(t)</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>t</tt> is equivalent to <tt>T(t)</tt>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
Copy constructor
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<pre>
|
||||
T(u)
|
||||
</pre>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>u</tt> is equivalent to <tt>T(u)</tt>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
Destructor
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<pre>
|
||||
t.~T()
|
||||
</pre>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
Address Operator
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<pre>
|
||||
&t
|
||||
</pre>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T*</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
denotes the address of <tt>t</tt>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD VAlign=top>
|
||||
Address Operator
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<pre>
|
||||
&u
|
||||
</pre>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
<tt>T*</tt>
|
||||
</TD>
|
||||
<TD VAlign=top>
|
||||
denotes the address of <tt>u</tt>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</table>
|
||||
<h3>Models</h3>
|
||||
|
||||
<UL>
|
||||
<LI><tt>int</tt>
|
||||
<LI><tt>std::pair</tt>
|
||||
</UL>
|
||||
|
||||
<h3>See also</h3>
|
||||
<A
|
||||
href="http://www.sgi.com/Technology/STL/DefaultConstructible.html">DefaultConstructible</A>
|
||||
and
|
||||
<A href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</A>
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
@ -1,92 +0,0 @@
|
||||
<HTML>
|
||||
<!--
|
||||
-- Copyright (c) Jeremy Siek 2000
|
||||
--
|
||||
-- Permission to use, copy, modify, distribute and sell this software
|
||||
-- and its documentation for any purpose is hereby granted without fee,
|
||||
-- provided that the above copyright notice appears in all copies and
|
||||
-- that both that copyright notice and this permission notice appear
|
||||
-- in supporting documentation. Silicon Graphics makes no
|
||||
-- representations about the suitability of this software for any
|
||||
-- purpose. It is provided "as is" without express or implied warranty.
|
||||
-->
|
||||
<Head>
|
||||
<Title>MultiPassInputIterator</Title>
|
||||
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
|
||||
ALINK="#ff0000">
|
||||
<IMG SRC="../../c++boost.gif"
|
||||
ALT="C++ Boost" width="277" height="86">
|
||||
|
||||
<BR Clear>
|
||||
|
||||
<H2>
|
||||
<A NAME="concept:MultiPassInputIterator"></A>
|
||||
MultiPassInputIterator
|
||||
</H2>
|
||||
|
||||
This concept is a refinement of <a
|
||||
href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</a>,
|
||||
adding the requirements that the iterator can be used to make multiple
|
||||
passes through a range, and that if <TT>it1 == it2</TT> and
|
||||
<TT>it1</TT> is dereferenceable then <TT>++it1 == ++it2</TT>. The
|
||||
MultiPassInputIterator is very similar to the <a
|
||||
href="http://www.sgi.com/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a>. The
|
||||
only difference is that a <a
|
||||
href="http://www.sgi.com/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a>
|
||||
requires the <TT>reference</TT> type to be <TT>value_type&</TT>, whereas
|
||||
MultiPassInputIterator is like <a
|
||||
href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</a>
|
||||
in that the <TT>reference</TT> type merely has to be convertible to
|
||||
<TT>value_type</TT>.
|
||||
|
||||
|
||||
<h3>Design Notes</h3>
|
||||
|
||||
comments by Valentin Bonnard:
|
||||
|
||||
<p> I think that introducing MultiPassInputIterator isn't the right
|
||||
solution. Do you also want to define MultiPassBidirectionnalIterator
|
||||
and MultiPassRandomAccessIterator ? I don't, definitly. It only
|
||||
confuses the issue. The problem lies into the existing hierarchy of
|
||||
iterators, which mixes movabillity, modifiabillity and lvalue-ness,
|
||||
and these are clearly independant.
|
||||
|
||||
<p> The terms Forward, Bidirectionnal and RandomAccess are about
|
||||
movabillity and shouldn't be used to mean anything else. In a
|
||||
completly orthogonal way, iterators can be immutable, mutable, or
|
||||
neither. Lvalueness of iterators is also orthogonal with
|
||||
immutabillity. With these clean concepts, your MultiPassInputIterator
|
||||
is just called a ForwardIterator.
|
||||
|
||||
<p>
|
||||
Other translations are:<br>
|
||||
std::ForwardIterator -> ForwardIterator & LvalueIterator<br>
|
||||
std::BidirectionnalIterator -> BidirectionnalIterator & LvalueIterator<br>
|
||||
std::RandomAccessIterator -> RandomAccessIterator & LvalueIterator<br>
|
||||
|
||||
<p>
|
||||
Note that in practice the only operation not allowed on my
|
||||
ForwardIterator which is allowed on std::ForwardIterator is
|
||||
<tt>&*it</tt>. I think that <tt>&*</tt> is rarely needed in generic code.
|
||||
|
||||
<p>
|
||||
reply by Jeremy Siek:
|
||||
|
||||
<p>
|
||||
The above analysis by Valentin is right on. Of course, there is
|
||||
the problem with backward compatibility. The current STL implementations
|
||||
are based on the old definition of ForwardIterator. The right course
|
||||
of action is to get ForwardIterator, etc. changed in the C++ standard.
|
||||
Once that is done we can drop MultiPassInputIterator.
|
||||
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
@ -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_array:
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,489 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>C++ Type traits</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
||||
|
||||
<h2 align="center">C++ Type traits</h2>
|
||||
<p align="center"><em>by John Maddock and Steve Cleary</em></p>
|
||||
<p align="center"><em>This is a draft of an article that will appear in a future
|
||||
issue of </em><a href="http://www.ddj.com"><em>Dr Dobb's Journal</em></a></p>
|
||||
<p>Generic programming (writing code which works with any data type meeting a
|
||||
set of requirements) has become the method of choice for providing reusable
|
||||
code. However, there are times in generic programming when "generic"
|
||||
just isn't good enough - sometimes the differences between types are too large
|
||||
for an efficient generic implementation. This is when the traits technique
|
||||
becomes important - by encapsulating those properties that need to be considered
|
||||
on a type by type basis inside a traits class, we can minimise the amount of
|
||||
code that has to differ from one type to another, and maximise the amount of
|
||||
generic code.</p>
|
||||
<p>Consider an example: when working with character strings, one common
|
||||
operation is to determine the length of a null terminated string. Clearly it's
|
||||
possible to write generic code that can do this, but it turns out that there are
|
||||
much more efficient methods available: for example, the C library functions <font size="2" face="Courier New">strlen</font>
|
||||
and <font size="2" face="Courier New">wcslen</font> are usually written in
|
||||
assembler, and with suitable hardware support can be considerably faster than a
|
||||
generic version written in C++. The authors of the C++ standard library realised
|
||||
this, and abstracted the properties of <font size="2" face="Courier New">char</font>
|
||||
and <font size="2" face="Courier New">wchar_t</font> into the class <font size="2" face="Courier New">char_traits</font>.
|
||||
Generic code that works with character strings can simply use <font size="2" face="Courier New">char_traits<>::length</font>
|
||||
to determine the length of a null terminated string, safe in the knowledge that
|
||||
specialisations of <font size="2" face="Courier New">char_traits</font> will use
|
||||
the most appropriate method available to them.</p>
|
||||
<h4>Type traits</h4>
|
||||
<p>Class <font size="2" face="Courier New">char_traits</font> is a classic
|
||||
example of a collection of type specific properties wrapped up in a single class
|
||||
- what Nathan Myers termed a <i>baggage class</i>[1]. In the Boost type-traits
|
||||
library, we[2] have written a set of very specific traits classes, each of which
|
||||
encapsulate a single trait from the C++ type system; for example, is a type a
|
||||
pointer or a reference type? Or does a type have a trivial constructor, or a
|
||||
const-qualifier? The type-traits classes share a unified design: each class has
|
||||
a single member <i>value</i>, a compile-time constant that is true if the type
|
||||
has the specified property, and false otherwise. As we will show, these classes
|
||||
can be used in generic programming to determine the properties of a given type
|
||||
and introduce optimisations that are appropriate for that case.</p>
|
||||
<p>The type-traits library also contains a set of classes that perform a
|
||||
specific transformation on a type; for example, they can remove a top-level
|
||||
const or volatile qualifier from a type. Each class that performs a
|
||||
transformation defines a single typedef-member <i>type</i> that is the result of
|
||||
the transformation. All of the type-traits classes are defined inside namespace <font size="2" face="Courier New">boost</font>;
|
||||
for brevity, namespace-qualification is omitted in most of the code samples
|
||||
given.</p>
|
||||
<h4>Implementation</h4>
|
||||
<p>There are far too many separate classes contained in the type-traits library
|
||||
to give a full implementation here - see the source code in the Boost library
|
||||
for the full details - however, most of the implementation is fairly repetitive
|
||||
anyway, so here we will just give you a flavour for how some of the classes are
|
||||
implemented. Beginning with possibly the simplest class in the library, is_void<T>
|
||||
has a member <i>value</i> that is true only if T is void.</p>
|
||||
<pre>template <typename T>
|
||||
struct is_void
|
||||
{ static const bool value = false; };
|
||||
|
||||
template <>
|
||||
struct is_void<void>
|
||||
{ static const bool value = true; };</pre>
|
||||
<p>Here we define a primary version of the template class <font size="2" face="Courier New">is_void</font>,
|
||||
and provide a full-specialisation when T is void. While full specialisation of a
|
||||
template class is an important technique, sometimes we need a solution that is
|
||||
halfway between a fully generic solution, and a full specialisation. This is
|
||||
exactly the situation for which the standards committee defined partial
|
||||
template-class specialisation. As an example, consider the class
|
||||
boost::is_pointer<T>: here we needed a primary version that handles all
|
||||
the cases where T is not a pointer, and a partial specialisation to handle all
|
||||
the cases where T is a pointer:</p>
|
||||
<pre>template <typename T>
|
||||
struct is_pointer
|
||||
{ static const bool value = false; };
|
||||
|
||||
template <typename T>
|
||||
struct is_pointer<T*>
|
||||
{ static const bool value = true; };</pre>
|
||||
<p>The syntax for partial specialisation is somewhat arcane and could easily
|
||||
occupy an article in its own right; like full specialisation, in order to write
|
||||
a partial specialisation for a class, you must first declare the primary
|
||||
template. The partial specialisation contains an extra <<EFBFBD>> after the
|
||||
class name that contains the partial specialisation parameters; these define the
|
||||
types that will bind to that partial specialisation rather than the default
|
||||
template. The rules for what can appear in a partial specialisation are somewhat
|
||||
convoluted, but as a rule of thumb if you can legally write two function
|
||||
overloads of the form:</p>
|
||||
<pre>void foo(T);
|
||||
void foo(U);</pre>
|
||||
<p>Then you can also write a partial specialisation of the form:</p>
|
||||
<pre>template <typename T>
|
||||
class c{ /*details*/ };
|
||||
|
||||
template <typename T>
|
||||
|
||||
class c<U>{ /*details*/ };</pre>
|
||||
<p>This rule is by no means foolproof, but it is reasonably simple to remember
|
||||
and close enough to the actual rule to be useful for everyday use.</p>
|
||||
<p>As a more complex example of partial specialisation consider the class
|
||||
remove_bounds<T>. This class defines a single typedef-member <i>type</i>
|
||||
that is the same type as T but with any top-level array bounds removed; this is
|
||||
an example of a traits class that performs a transformation on a type:</p>
|
||||
<pre>template <typename T>
|
||||
struct remove_bounds
|
||||
{ typedef T type; };
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct remove_bounds<T[N]>
|
||||
{ typedef T type; };</pre>
|
||||
<p>The aim of remove_bounds is this: imagine a generic algorithm that is passed
|
||||
an array type as a template parameter, <font size="2" face="Courier New">remove_bounds</font>
|
||||
provides a means of determining the underlying type of the array. For example <code>remove_bounds<int[4][5]>::type</code>
|
||||
would evaluate to the type <code>int[5]</code>. This example also shows that the
|
||||
number of template parameters in a partial specialisation does not have to match
|
||||
the number in the default template. However, the number of parameters that
|
||||
appear after the class name do have to match the number and type of the
|
||||
parameters in the default template.</p>
|
||||
<h4>Optimised copy</h4>
|
||||
<p>As an example of how the type traits classes can be used, consider the
|
||||
standard library algorithm copy:</p>
|
||||
<pre>template<typename Iter1, typename Iter2>
|
||||
Iter2 copy(Iter1 first, Iter1 last, Iter2 out);</pre>
|
||||
<p>Obviously, there's no problem writing a generic version of copy that works
|
||||
for all iterator types Iter1 and Iter2; however, there are some circumstances
|
||||
when the copy operation can best be performed by a call to <font size="2" face="Courier New">memcpy</font>.
|
||||
In order to implement copy in terms of <font size="2" face="Courier New">memcpy</font>
|
||||
all of the following conditions need to be met:</p>
|
||||
<ul>
|
||||
<li>Both of the iterator types Iter1 and Iter2 must be pointers.</li>
|
||||
<li>Both Iter1 and Iter2 must point to the same type - excluding <font size="2" face="Courier New">const</font>
|
||||
and <font size="2" face="Courier New">volatile</font>-qualifiers.</li>
|
||||
<li>The type pointed to by Iter1 must have a trivial assignment operator.</li>
|
||||
</ul>
|
||||
<p>By trivial assignment operator we mean that the type is either a scalar
|
||||
type[3] or:</p>
|
||||
<ul>
|
||||
<li>The type has no user defined assignment operator.</li>
|
||||
<li>The type does not have any data members that are references.</li>
|
||||
<li>All base classes, and all data member objects must have trivial assignment
|
||||
operators.</li>
|
||||
</ul>
|
||||
<p>If all these conditions are met then a type can be copied using <font size="2" face="Courier New">memcpy</font>
|
||||
rather than using a compiler generated assignment operator. The type-traits
|
||||
library provides a class <i>has_trivial_assign</i>, such that <code>has_trivial_assign<T>::value</code>
|
||||
is true only if T has a trivial assignment operator. This class "just
|
||||
works" for scalar types, but has to be explicitly specialised for
|
||||
class/struct types that also happen to have a trivial assignment operator. In
|
||||
other words if <i>has_trivial_assign</i> gives the wrong answer, it will give
|
||||
the "safe" wrong answer - that trivial assignment is not allowable.</p>
|
||||
<p>The code for an optimised version of copy that uses <font size="2" face="Courier New">memcpy</font>
|
||||
where appropriate is given in listing 1. The code begins by defining a template
|
||||
class <i>copier</i>, that takes a single Boolean template parameter, and has a
|
||||
static template member function <font size="2" face="Courier New">do_copy</font>
|
||||
which performs the generic version of <font size="2">copy</font> (in other words
|
||||
the "slow but safe version"). Following that there is a specialisation
|
||||
for <i>copier<true></i>: again this defines a static template member
|
||||
function <font size="2" face="Courier New">do_copy</font>, but this version uses
|
||||
memcpy to perform an "optimised" copy.</p>
|
||||
<p>In order to complete the implementation, what we need now is a version of
|
||||
copy, that calls <code>copier<true>::do_copy</code> if it is safe to use <font size="2" face="Courier New">memcpy</font>,
|
||||
and otherwise calls <code>copier<false>::do_copy</code> to do a
|
||||
"generic" copy. This is what the version in listing 1 does. To
|
||||
understand how the code works look at the code for <font size="2" face="Courier New">copy</font>
|
||||
and consider first the two typedefs <i>v1_t</i> and <i>v2_t</i>. These use <code>std::iterator_traits<Iter1>::value_type</code>
|
||||
to determine what type the two iterators point to, and then feed the result into
|
||||
another type-traits class <i>remove_cv</i> that removes the top-level
|
||||
const-volatile-qualifiers: this will allow copy to compare the two types without
|
||||
regard to const- or volatile-qualifiers. Next, <font size="2" face="Courier New">copy</font>
|
||||
declares an enumerated value <i>can_opt</i> that will become the template
|
||||
parameter to copier - declaring this here as a constant is really just a
|
||||
convenience - the value could be passed directly to class <font size="2" face="Courier New">copier</font>.
|
||||
The value of <i>can_opt</i> is computed by verifying that all of the following
|
||||
are true:</p>
|
||||
<ul>
|
||||
<li>first that the two iterators point to the same type by using a type-traits
|
||||
class <i>is_same</i>.</li>
|
||||
<li>Then that both iterators are real pointers - using the class <i>is_pointer</i>
|
||||
described above.</li>
|
||||
<li>Finally that the pointed-to types have a trivial assignment operator using
|
||||
<i>has_trivial_assign</i>.</li>
|
||||
</ul>
|
||||
<p>Finally we can use the value of <i>can_opt</i> as the template argument to
|
||||
copier - this version of copy will now adapt to whatever parameters are passed
|
||||
to it, if its possible to use <font size="2" face="Courier New">memcpy</font>,
|
||||
then it will do so, otherwise it will use a generic copy.</p>
|
||||
<h4>Was it worth it?</h4>
|
||||
<p>It has often been repeated in these columns that "premature optimisation
|
||||
is the root of all evil" [4]. So the question must be asked: was our
|
||||
optimisation premature? To put this in perspective the timings for our version
|
||||
of copy compared a conventional generic copy[5] are shown in table 1.</p>
|
||||
<p>Clearly the optimisation makes a difference in this case; but, to be fair,
|
||||
the timings are loaded to exclude cache miss effects - without this accurate
|
||||
comparison between algorithms becomes difficult. However, perhaps we can add a
|
||||
couple of caveats to the premature optimisation rule:</p>
|
||||
<ul>
|
||||
<li>If you use the right algorithm for the job in the first place then
|
||||
optimisation will not be required; in some cases, <font size="2" face="Courier New">memcpy</font>
|
||||
is the right algorithm.</li>
|
||||
<li>If a component is going to be reused in many places by many people then
|
||||
optimisations may well be worthwhile where they would not be so for a single
|
||||
case - in other words, the likelihood that the optimisation will be
|
||||
absolutely necessary somewhere, sometime is that much higher. Just as
|
||||
importantly the perceived value of the stock implementation will be higher:
|
||||
there is no point standardising an algorithm if users reject it on the
|
||||
grounds that there are better, more heavily optimised versions available.</li>
|
||||
</ul>
|
||||
<h4>Table 1: Time taken to copy 1000 elements using copy<const T*, T*>
|
||||
(times in micro-seconds)</h4>
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="529">
|
||||
<tr>
|
||||
<td valign="top" width="33%">
|
||||
<p align="center">Version</p>
|
||||
</td>
|
||||
<td valign="top" width="33%">
|
||||
<p align="center">T</p>
|
||||
</td>
|
||||
<td valign="top" width="33%">
|
||||
<p align="center">Time</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">"Optimised" copy</td>
|
||||
<td valign="top" width="33%">char</td>
|
||||
<td valign="top" width="33%">0.99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">Conventional copy</td>
|
||||
<td valign="top" width="33%">char</td>
|
||||
<td valign="top" width="33%">8.07</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">"Optimised" copy</td>
|
||||
<td valign="top" width="33%">int</td>
|
||||
<td valign="top" width="33%">2.52</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">Conventional copy</td>
|
||||
<td valign="top" width="33%">int</td>
|
||||
<td valign="top" width="33%">8.02</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </p>
|
||||
<h4>Pair of References</h4>
|
||||
<p>The optimised copy example shows how type traits may be used to perform
|
||||
optimisation decisions at compile-time. Another important usage of type traits
|
||||
is to allow code to compile that otherwise would not do so unless excessive
|
||||
partial specialization is used. This is possible by delegating partial
|
||||
specialization to the type traits classes. Our example for this form of usage is
|
||||
a pair that can hold references [6].</p>
|
||||
<p>First, let us examine the definition of "std::pair", omitting the
|
||||
comparision operators, default constructor, and template copy constructor for
|
||||
simplicity:</p>
|
||||
<pre>template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
pair(const T1 & nfirst, const T2 & nsecond)
|
||||
:first(nfirst), second(nsecond) { }
|
||||
};</pre>
|
||||
<p>Now, this "pair" cannot hold references as it currently stands,
|
||||
because the constructor would require taking a reference to a reference, which
|
||||
is currently illegal [7]. Let us consider what the constructor's parameters
|
||||
would have to be in order to allow "pair" to hold non-reference types,
|
||||
references, and constant references:</p>
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="638">
|
||||
<tr>
|
||||
<td valign="top" width="50%">Type of "T1"</td>
|
||||
<td valign="top" width="50%">Type of parameter to initializing constructor</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<pre>T</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<pre>T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<pre>T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>A little familiarity with the type traits classes allows us to construct a
|
||||
single mapping that allows us to determine the type of parameter from the type
|
||||
of the contained class. The type traits classes provide a transformation "add_reference",
|
||||
which adds a reference to its type, unless it is already a reference.</p>
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="580">
|
||||
<tr>
|
||||
<td valign="top" width="21%">Type of "T1"</td>
|
||||
<td valign="top" width="27%">Type of "const T1"</td>
|
||||
<td valign="top" width="53%">Type of "add_reference<const
|
||||
T1>::type"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%">
|
||||
<pre>T</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%">
|
||||
<pre>const T</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%">
|
||||
<pre>T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%">
|
||||
<pre>T & [8]</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%">
|
||||
<pre>T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%">
|
||||
<pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This allows us to build a primary template definition for "pair"
|
||||
that can contain non-reference types, reference types, and constant reference
|
||||
types:</p>
|
||||
<pre>template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
pair(boost::add_reference<const T1>::type nfirst,
|
||||
boost::add_reference<const T2>::type nsecond)
|
||||
:first(nfirst), second(nsecond) { }
|
||||
};</pre>
|
||||
<p>Add back in the standard comparision operators, default constructor, and
|
||||
template copy constructor (which are all the same), and you have a std::pair
|
||||
that can hold reference types!</p>
|
||||
<p>This same extension <i>could</i> have been done using partial template
|
||||
specialization of "pair", but to specialize "pair" in this
|
||||
way would require three partial specializations, plus the primary template. Type
|
||||
traits allows us to define a single primary template that adjusts itself
|
||||
auto-magically to any of these partial specializations, instead of a brute-force
|
||||
partial specialization approach. Using type traits in this fashion allows
|
||||
programmers to delegate partial specialization to the type traits classes,
|
||||
resulting in code that is easier to maintain and easier to understand.</p>
|
||||
<h4>Conclusion</h4>
|
||||
<p>We hope that in this article we have been able to give you some idea of what
|
||||
type-traits are all about. A more complete listing of the available classes are
|
||||
in the boost documentation, along with further examples using type traits.
|
||||
Templates have enabled C++ uses to take the advantage of the code reuse that
|
||||
generic programming brings; hopefully this article has shown that generic
|
||||
programming does not have to sink to the lowest common denominator, and that
|
||||
templates can be optimal as well as generic.</p>
|
||||
<h4>Acknowledgements</h4>
|
||||
<p>The authors would like to thank Beman Dawes and Howard Hinnant for their
|
||||
helpful comments when preparing this article.</p>
|
||||
<h4>References</h4>
|
||||
<ol>
|
||||
<li>Nathan C. Myers, C++ Report, June 1995.</li>
|
||||
<li>The type traits library is based upon contributions by Steve Cleary, Beman
|
||||
Dawes, Howard Hinnant and John Maddock: it can be found at www.boost.org.</li>
|
||||
<li>A scalar type is an arithmetic type (i.e. a built-in integer or floating
|
||||
point type), an enumeration type, a pointer, a pointer to member, or a
|
||||
const- or volatile-qualified version of one of these types.</li>
|
||||
<li>This quote is from Donald Knuth, ACM Computing Surveys, December 1974, pg
|
||||
268.</li>
|
||||
<li>The test code is available as part of the boost utility library (see
|
||||
algo_opt_examples.cpp), the code was compiled with gcc 2.95 with all
|
||||
optimisations turned on, tests were conducted on a 400MHz Pentium II machine
|
||||
running Microsoft Windows 98.</li>
|
||||
<li>John Maddock and Howard Hinnant have submitted a "compressed_pair"
|
||||
library to Boost, which uses a technique similar to the one described here
|
||||
to hold references. Their pair also uses type traits to determine if any of
|
||||
the types are empty, and will derive instead of contain to conserve space --
|
||||
hence the name "compressed".</li>
|
||||
<li>This is actually an issue with the C++ Core Language Working Group (issue
|
||||
#106), submitted by Bjarne Stroustrup. The tentative resolution is to allow
|
||||
a "reference to a reference to T" to mean the same thing as a
|
||||
"reference to T", but only in template instantiation, in a method
|
||||
similar to multiple cv-qualifiers.</li>
|
||||
<li>For those of you who are wondering why this shouldn't be const-qualified,
|
||||
remember that references are always implicitly constant (for example, you
|
||||
can't re-assign a reference). Remember also that "const T &"
|
||||
is something completely different. For this reason, cv-qualifiers on
|
||||
template type arguments that are references are ignored.</li>
|
||||
</ol>
|
||||
<h2>Listing 1</h2>
|
||||
<pre>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);
|
||||
}</pre>
|
||||
<hr>
|
||||
<p><EFBFBD> Copyright John Maddock and Steve Cleary, 2000</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
738
call_traits.htm
738
call_traits.htm
@ -1,738 +0,0 @@
|
||||
<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>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. Note that for compilers that do not support partial
|
||||
specialization, 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.</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<Operation::second_argument_type, Operation::result_type>
|
||||
{
|
||||
protected:
|
||||
Operation op;
|
||||
Operation::first_argument_type value;
|
||||
public:
|
||||
binder1st(const Operation& x, const Operation::first_argument_type& y);
|
||||
Operation::result_type operator()(const 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>Operation::result_type operator()(call_traits<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.</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>
|
||||
|
||||
<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(call_traits<T>::value_type t);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void A<T>::foo(call_traits<T>::value_type t)
|
||||
{
|
||||
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 18 June 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.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p>
|
||||
|
||||
<p>.</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
@ -1,355 +0,0 @@
|
||||
// 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>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <typeinfo>
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
#include "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:
|
||||
//
|
||||
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()const { return v_; }
|
||||
// return by_ref:
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
// pass value:
|
||||
void call(param_type p){}
|
||||
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T, std::size_t N>
|
||||
struct contained<T[N]>
|
||||
{
|
||||
typedef typename boost::call_traits<T[N]>::param_type param_type;
|
||||
typedef typename boost::call_traits<T[N]>::reference reference;
|
||||
typedef typename boost::call_traits<T[N]>::const_reference const_reference;
|
||||
typedef T value_type[N];
|
||||
typedef typename boost::call_traits<T[N]>::value_type result_type;
|
||||
|
||||
value_type v_;
|
||||
|
||||
contained(param_type p)
|
||||
{
|
||||
std::copy(p, p+N, v_);
|
||||
}
|
||||
// return byval:
|
||||
result_type value()const { return v_; }
|
||||
// return by_ref:
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
void call(param_type p){}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
contained<typename boost::call_traits<T>::value_type> wrap(const T& t)
|
||||
{
|
||||
typedef typename boost::call_traits<T>::value_type ct;
|
||||
return contained<ct>(t);
|
||||
}
|
||||
|
||||
namespace test{
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
using namespace std;
|
||||
|
||||
//
|
||||
// struct checker:
|
||||
// verifies behaviour of contained example:
|
||||
//
|
||||
template <class T>
|
||||
struct 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)
|
||||
{
|
||||
T t(p);
|
||||
contained<T> c(t);
|
||||
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T, std::size_t N>
|
||||
struct checker<T[N]>
|
||||
{
|
||||
typedef typename boost::call_traits<T[N]>::param_type param_type;
|
||||
void operator()(param_type t)
|
||||
{
|
||||
contained<T[N]> c(t);
|
||||
cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl;
|
||||
unsigned int i = 0;
|
||||
for(i = 0; i < N; ++i)
|
||||
assert(t[i] == c.value()[i]);
|
||||
for(i = 0; i < N; ++i)
|
||||
assert(t[i] == c.get()[i]);
|
||||
for(i = 0; i < N; ++i)
|
||||
assert(t[i] == c.const_get()[i]);
|
||||
|
||||
cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained<T[N]>::v_).name() << endl;
|
||||
cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained<T[N]>::value).name() << endl;
|
||||
cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained<T[N]>::get).name() << endl;
|
||||
cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained<T[N]>::const_get).name() << endl;
|
||||
cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained<T[N]>::call).name() << endl;
|
||||
cout << endl;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// check_wrap:
|
||||
template <class T, class U>
|
||||
void check_wrap(const contained<T>& w, const U& u)
|
||||
{
|
||||
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
|
||||
assert(w.value() == u);
|
||||
}
|
||||
|
||||
//
|
||||
// check_make_pair:
|
||||
// verifies behaviour of "make_pair":
|
||||
//
|
||||
template <class T, class U, class V>
|
||||
void check_make_pair(T c, U u, V v)
|
||||
{
|
||||
cout << "checking std::pair<" << typeid(c.first).name() << ", " << typeid(c.second).name() << ">..." << endl;
|
||||
assert(c.first == u);
|
||||
assert(c.second == v);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
|
||||
struct UDT
|
||||
{
|
||||
int i_;
|
||||
UDT() : i_(2){}
|
||||
bool operator == (const UDT& v){ return v.i_ == i_; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
checker<UDT> c1;
|
||||
UDT u;
|
||||
c1(u);
|
||||
checker<int> c2;
|
||||
int i = 2;
|
||||
c2(i);
|
||||
int* pi = &i;
|
||||
checker<int*> c3;
|
||||
c3(pi);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
checker<int&> c4;
|
||||
c4(i);
|
||||
checker<const int&> c5;
|
||||
c5(i);
|
||||
|
||||
int a[2] = {1,2};
|
||||
checker<int[2]> c6;
|
||||
c6(a);
|
||||
#endif
|
||||
|
||||
check_wrap(wrap(2), 2);
|
||||
const char ca[4] = "abc";
|
||||
// compiler can't deduce this for some reason:
|
||||
//check_wrap(wrap(ca), ca);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
check_wrap(wrap(a), a);
|
||||
check_make_pair(test::make_pair(a, a), a, a);
|
||||
#endif
|
||||
|
||||
// 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(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(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)
|
||||
type_test(const int, boost::call_traits<int>::param_type)
|
||||
type_test(int*, boost::call_traits<int*>::value_type)
|
||||
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
|
||||
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)
|
||||
type_test(int&, boost::call_traits<int&>::param_type)
|
||||
#if !(defined(__GNUC__) && (__GNUC__ < 3))
|
||||
type_test(int&, boost::call_traits<cr_type>::value_type)
|
||||
type_test(int&, boost::call_traits<cr_type>::reference)
|
||||
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
||||
type_test(int&, boost::call_traits<cr_type>::param_type)
|
||||
#else
|
||||
std::cout << "Your compiler cannot instantiate call_traits<int&const>, skipping four tests (4 errors)" << std::endl;
|
||||
failures += 4;
|
||||
test_count += 4;
|
||||
#endif
|
||||
type_test(const int&, boost::call_traits<const int&>::value_type)
|
||||
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)
|
||||
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)
|
||||
type_test(const int*const, boost::call_traits<int[3]>::param_type)
|
||||
type_test(const int*, boost::call_traits<const int[3]>::value_type)
|
||||
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 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;
|
||||
}
|
||||
|
||||
//
|
||||
// define call_traits tests to check that the assertions in the docs do actually work
|
||||
// this is an instantiate only set of tests:
|
||||
//
|
||||
template <typename T, bool isarray = false>
|
||||
struct call_traits_test
|
||||
{
|
||||
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(typename call_traits_test<T, isarray>::param_type val)
|
||||
{
|
||||
//
|
||||
// this is to check that the call_traits assertions are valid:
|
||||
T t(val);
|
||||
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>
|
||||
{
|
||||
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)
|
||||
{
|
||||
//
|
||||
// this is to check that the call_traits assertions are valid:
|
||||
T t;
|
||||
value_type v(t);
|
||||
value_type v5(val);
|
||||
reference r = t;
|
||||
const_reference cr = t;
|
||||
reference r2 = r;
|
||||
#ifndef __BORLANDC__
|
||||
// C++ Builder buglet:
|
||||
const_reference cr2 = r;
|
||||
#endif
|
||||
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
|
||||
template struct call_traits_test<int&>;
|
||||
template struct call_traits_test<const int&>;
|
||||
template struct call_traits_test<int[2], true>;
|
||||
#endif
|
||||
|
148
cast.htm
148
cast.htm
@ -1,148 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>Header boost/cast.hpp Documentation</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
|
||||
<a href="../../boost/cast.hpp">boost/cast.hpp</a></h1>
|
||||
<h2><a name="Cast Functions">Cast Functions</a></h2>
|
||||
<p>The <code>header <a href="../../boost/cast.hpp">boost/cast.hpp</a></code>
|
||||
provides <a href="#Polymorphic_cast"><b>polymorphic_cast</b></a>, <a href="#Polymorphic_cast"><b>polymorphic_downcast</b></a>,
|
||||
and <a href="#numeric_cast"><b>numeric_cast</b></a> template functions designed
|
||||
to complement the C++ Standard's built-in casts.</p>
|
||||
<p>The program <a href="cast_test.cpp">cast_test.cpp</a> can be used to
|
||||
verify these function templates work as expected.</p>
|
||||
<p><b>polymorphic_cast</b> was suggested by Bjarne Stroustrup in "The C++
|
||||
Programming Language".<br>
|
||||
<b>polymorphic_downcast</b> was contributed by <a href="../../people/dave_abrahams.htm">Dave
|
||||
Abrahams</a>.<b><br>
|
||||
numeric_cast</b> was contributed by <a href="../../people/kevlin_henney.htm">Kevlin
|
||||
Henney</a>.</p>
|
||||
<h3>Namespace synopsis</h3>
|
||||
<blockquote>
|
||||
<pre>namespace boost {
|
||||
namespace cast {
|
||||
// all synopsis below included here
|
||||
}
|
||||
using ::boost::cast::polymorphic_cast;
|
||||
using ::boost::cast::polymorphic_downcast;
|
||||
using ::boost::cast::bad_numeric_cast;
|
||||
using ::boost::cast::numeric_cast;
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<h3><a name="Polymorphic_cast">Polymorphic casts</a></h3>
|
||||
<p>Pointers to polymorphic objects (objects of classes which define at least one
|
||||
virtual function) are sometimes downcast or crosscast. Downcasting means
|
||||
casting from a base class to a derived class. Crosscasting means casting
|
||||
across an inheritance hierarchy diagram, such as from one base to the other in a
|
||||
<b>Y</b> diagram hierarchy.</p>
|
||||
<p>Such casts can be done with old-style casts, but this approach is never to be
|
||||
recommended. Old-style casts are sorely lacking in type safety, suffer
|
||||
poor readability, and are difficult to locate with search tools.</p>
|
||||
<p>The C++ built-in <b>static_cast</b> can be used for efficiently downcasting
|
||||
pointers to polymorphic objects, but provides no error detection for the case
|
||||
where the pointer being cast actually points to the wrong derived class. The <b>polymorphic_downcast</b>
|
||||
template retains the efficiency of <b>static_cast</b> for non-debug
|
||||
compilations, but for debug compilations adds safety via an assert() that a <b>dynamic_cast</b>
|
||||
succeeds. <b> </b></p>
|
||||
<p>The C++ built-in <b>dynamic_cast</b> can be used for downcasts and crosscasts
|
||||
of pointers to polymorphic objects, but error notification in the form of a
|
||||
returned value of 0 is inconvenient to test, or worse yet, easy to forget to
|
||||
test. The <b>polymorphic_cast</b> template performs a <b>dynamic_cast</b>,
|
||||
and throws an exception if the <b>dynamic_cast</b> returns 0.</p>
|
||||
<p>A <b>polymorphic_downcast</b> is preferred when debug-mode tests will cover
|
||||
100% of the object types possibly cast and when non-debug-mode efficiency is an
|
||||
issue. If these two conditions are not present, <b>polymorphic_cast</b> is
|
||||
preferred. It must also be used for crosscasts. It does an assert(
|
||||
dynamic_cast<Derived>(x) == x ) where x is the base pointer, ensuring that
|
||||
not only is a non-zero pointer returned, but also that it correct in the
|
||||
presence of multiple inheritance. .<b> Warning:</b>: Because <b>polymorphic_downcast</b>
|
||||
uses assert(), it violates the One Definition Rule if NDEBUG is inconsistently
|
||||
defined across translation units.</p>
|
||||
<p>The C++ built-in <b>dynamic_cast</b> must be used to cast references rather
|
||||
than pointers. It is also the only cast that can be used to check whether
|
||||
a given interface is supported; in that case a return of 0 isn't an error
|
||||
condition.</p>
|
||||
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
|
||||
<blockquote>
|
||||
<pre>template <class Derived, class Base>
|
||||
inline Derived polymorphic_cast(Base* x);
|
||||
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
|
||||
// Returns: dynamic_cast<Derived>(x)
|
||||
|
||||
template <class Derived, class Base>
|
||||
inline Derived polymorphic_downcast(Base* x);
|
||||
// Effects: assert( dynamic_cast<Derived>(x) == x );
|
||||
// Returns: static_cast<Derived>(x)</pre>
|
||||
</blockquote>
|
||||
<h3>polymorphic_downcast example</h3>
|
||||
<blockquote>
|
||||
<pre>#include <boost/cast.hpp>
|
||||
...
|
||||
class Fruit { public: virtual ~Fruit(){}; ... };
|
||||
class Banana : public Fruit { ... };
|
||||
...
|
||||
void f( Fruit * fruit ) {
|
||||
// ... logic which leads us to believe it is a Banana
|
||||
Banana * banana = boost::polymorphic_downcast<Banana*>(fruit);
|
||||
...</pre>
|
||||
</blockquote>
|
||||
<h3><a name="numeric_cast">numeric_cast</a></h3>
|
||||
<p>A <b>static_cast</b>, <b>implicit_cast</b> or implicit conversion will not
|
||||
detect failure to preserve range for numeric casts. The <b>numeric_cast</b>
|
||||
template function are similar to <b>static_cast</b> and certain (dubious)
|
||||
implicit conversions in this respect, except that they detect loss of numeric
|
||||
range. An exception is thrown when a runtime value preservation check fails.</p>
|
||||
<p>The requirements on the argument and result types are:</p>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>Both argument and result types are CopyConstructible [20.1.3].</li>
|
||||
<li>Both argument and result types are Numeric, defined by <code>std::numeric_limits<>::is_specialized</code>
|
||||
being true.</li>
|
||||
<li>The argument can be converted to the result type using <b>static_cast</b>.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<h3>numeric_cast synopsis</h3>
|
||||
<blockquote>
|
||||
<pre>class bad_numeric_cast : public std::bad_cast {...};
|
||||
|
||||
template<typename Target, typename Source>
|
||||
inline Target numeric_cast(Source arg);
|
||||
// Throws: bad_numeric_cast unless, in converting arg from Source to Target,
|
||||
// there is no loss of negative range, and no underflow, and no
|
||||
// overflow, as determined by std::numeric_limits
|
||||
// Returns: static_cast<Target>(arg)</pre>
|
||||
</blockquote>
|
||||
<h3>numeric_cast example</h3>
|
||||
<blockquote>
|
||||
<pre>#include <boost/cast.hpp>
|
||||
using namespace boost::cast;
|
||||
|
||||
void ariane(double vx)
|
||||
{
|
||||
...
|
||||
unsigned short dx = numeric_cast<unsigned short>(vx);
|
||||
...
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<h3>numeric_cast rationale</h3>
|
||||
<p>The form of the throws condition is specified so that != is not a required
|
||||
operation.</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan
|
||||
-->28 June, 2000<!--webbot bot="Timestamp" endspan i-checksum="19846"
|
||||
--></p>
|
||||
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
|
||||
distribute this document is granted provided this copyright notice appears in
|
||||
all copies. This document is provided "as is" without express or
|
||||
implied warranty, and with no claim as to its suitability for any purpose.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
149
cast_test.cpp
149
cast_test.cpp
@ -1,149 +0,0 @@
|
||||
// boost utility cast test program -----------------------------------------//
|
||||
|
||||
// (C) Copyright boost.org 1999. Permission to copy, use, modify, sell
|
||||
// and distribute this software is granted provided this copyright
|
||||
// notice appears in all copies. This software is provided "as is" without
|
||||
// express or implied warranty, and with no claim as to its suitability for
|
||||
// any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 28 Jun 00 implicit_cast removed (Beman Dawes)
|
||||
// 30 Aug 99 value_cast replaced by numeric_cast
|
||||
// 3 Aug 99 Initial Version
|
||||
|
||||
#include <iostream>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <boost/cast.hpp>
|
||||
|
||||
# if SCHAR_MAX == LONG_MAX
|
||||
# error "This test program doesn't work if SCHAR_MAX == LONG_MAX"
|
||||
# endif
|
||||
|
||||
using namespace boost;
|
||||
using std::cout;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Base
|
||||
{
|
||||
virtual char kind() { return 'B'; }
|
||||
};
|
||||
|
||||
struct Base2
|
||||
{
|
||||
virtual char kind2() { return '2'; }
|
||||
};
|
||||
|
||||
struct Derived : public Base, Base2
|
||||
{
|
||||
virtual char kind() { return 'D'; }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
cout << "Usage: test_casts [n], where n omitted or is:\n"
|
||||
" 1 = execute #1 assert failure (#ifndef NDEBUG)\n"
|
||||
" 2 = execute #2 assert failure (#ifndef NDEBUG)\n"
|
||||
"Example: test_casts 2\n\n";
|
||||
|
||||
# ifdef NDEBUG
|
||||
cout << "NDEBUG is defined\n";
|
||||
# else
|
||||
cout << "NDEBUG is not defined\n";
|
||||
# endif
|
||||
|
||||
cout << "\nBeginning tests...\n";
|
||||
|
||||
// test polymorphic_cast ---------------------------------------------------//
|
||||
|
||||
// tests which should succeed
|
||||
Base * base = new Derived;
|
||||
Base2 * base2 = 0;
|
||||
Derived * derived = 0;
|
||||
derived = polymorphic_downcast<Derived*>( base ); // downcast
|
||||
assert( derived->kind() == 'D' );
|
||||
|
||||
derived = 0;
|
||||
derived = polymorphic_cast<Derived*>( base ); // downcast, throw on error
|
||||
assert( derived->kind() == 'D' );
|
||||
|
||||
base2 = polymorphic_cast<Base2*>( base ); // crosscast
|
||||
assert( base2->kind2() == '2' );
|
||||
|
||||
// tests which should result in errors being detected
|
||||
int err_count = 0;
|
||||
base = new Base;
|
||||
|
||||
if ( argc > 1 && *argv[1] == '1' )
|
||||
{ derived = polymorphic_downcast<Derived*>( base ); } // #1 assert failure
|
||||
|
||||
bool caught_exception = false;
|
||||
try { derived = polymorphic_cast<Derived*>( base ); }
|
||||
catch (std::bad_cast)
|
||||
{ cout<<"caught bad_cast\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
// the following is just so generated code can be inspected
|
||||
if ( derived->kind() == 'B' ) ++err_count;
|
||||
|
||||
// test implicit_cast and numeric_cast -------------------------------------//
|
||||
|
||||
// tests which should succeed
|
||||
long small_value = 1;
|
||||
long small_negative_value = -1;
|
||||
long large_value = std::numeric_limits<long>::max();
|
||||
long large_negative_value = std::numeric_limits<long>::min();
|
||||
signed char c = 0;
|
||||
|
||||
c = large_value; // see if compiler generates warning
|
||||
|
||||
c = numeric_cast<signed char>( small_value );
|
||||
assert( c == 1 );
|
||||
c = 0;
|
||||
c = numeric_cast<signed char>( small_value );
|
||||
assert( c == 1 );
|
||||
c = 0;
|
||||
c = numeric_cast<signed char>( small_negative_value );
|
||||
assert( c == -1 );
|
||||
|
||||
// tests which should result in errors being detected
|
||||
|
||||
caught_exception = false;
|
||||
try { c = numeric_cast<signed char>( large_value ); }
|
||||
catch (bad_numeric_cast)
|
||||
{ cout<<"caught bad_numeric_cast #1\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
|
||||
caught_exception = false;
|
||||
try { c = numeric_cast<signed char>( large_negative_value ); }
|
||||
catch (bad_numeric_cast)
|
||||
{ cout<<"caught bad_numeric_cast #2\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
|
||||
unsigned long ul;
|
||||
caught_exception = false;
|
||||
try { ul = numeric_cast<unsigned long>( large_negative_value ); }
|
||||
catch (bad_numeric_cast)
|
||||
{ cout<<"caught bad_numeric_cast #3\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
|
||||
caught_exception = false;
|
||||
try { ul = numeric_cast<unsigned long>( small_negative_value ); }
|
||||
catch (bad_numeric_cast)
|
||||
{ cout<<"caught bad_numeric_cast #4\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
|
||||
caught_exception = false;
|
||||
try { numeric_cast<int>( std::numeric_limits<double>::max() ); }
|
||||
catch (bad_numeric_cast)
|
||||
{ cout<<"caught bad_numeric_cast #5\n"; caught_exception = true; }
|
||||
if ( !caught_exception ) ++err_count;
|
||||
|
||||
cout << err_count << " errors detected\nTest "
|
||||
<< (err_count==0 ? "passed\n" : "failed\n");
|
||||
return err_count;
|
||||
} // main
|
@ -1,92 +0,0 @@
|
||||
<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 <boost/compressed_pair.hpp></title>
|
||||
</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/call_traits.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);
|
||||
|
||||
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 an enumerator type, unless there is
|
||||
compiler support for boost::is_enum, or if boost::is_enum is
|
||||
specialised for the enumerator type.</p>
|
||||
|
||||
<p>Finally, compressed_pair requires compiler support for partial
|
||||
specialisation of class templates - without that support
|
||||
compressed_pair behaves just like std::pair.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 08 March 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.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p>
|
||||
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
@ -1,127 +0,0 @@
|
||||
// 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/compressed_pair.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/compressed_pair.hpp>
|
||||
#include "type_traits_test.hpp"
|
||||
|
||||
using namespace boost;
|
||||
|
||||
struct empty_POD_UDT{};
|
||||
struct empty_UDT
|
||||
{
|
||||
~empty_UDT(){};
|
||||
};
|
||||
namespace boost {
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
template <> struct is_empty<empty_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_empty<empty_POD_UDT>
|
||||
{ static const bool value = true; };
|
||||
template <> struct is_POD<empty_POD_UDT>
|
||||
{ static const bool value = true; };
|
||||
#else
|
||||
template <> struct is_empty<empty_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_empty<empty_POD_UDT>
|
||||
{ enum{ value = true }; };
|
||||
template <> struct is_POD<empty_POD_UDT>
|
||||
{ enum{ value = true }; };
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
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> >)))
|
||||
|
||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||
std::cin.get();
|
||||
return failures;
|
||||
}
|
||||
|
||||
//
|
||||
// instanciate some compressed pairs:
|
||||
#ifdef __MWERKS__
|
||||
template class compressed_pair<int, double>;
|
||||
template class compressed_pair<int, int>;
|
||||
template class compressed_pair<empty_UDT, int>;
|
||||
template class compressed_pair<int, empty_UDT>;
|
||||
template class compressed_pair<empty_UDT, empty_UDT>;
|
||||
template class compressed_pair<empty_UDT, empty_POD_UDT>;
|
||||
#else
|
||||
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>;
|
||||
#endif
|
||||
|
||||
#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 __MWERKS__
|
||||
#ifndef __BORLANDC__
|
||||
template call_traits<int[2]>::reference compressed_pair<double, int[2]>::second();
|
||||
#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 // __MWERKS__
|
||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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,10 +1,9 @@
|
||||
// (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.
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// See http://www.boost.org/libs/utility for most recent version including documentation.
|
||||
|
||||
// call_traits: defines typedefs for function usage
|
||||
// (see libs/utility/call_traits.htm)
|
||||
@ -22,29 +21,42 @@
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#endif
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <typename T, bool isp, bool b1, bool b2>
|
||||
template <typename T, bool small_>
|
||||
struct ct_imp2
|
||||
{
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ct_imp2<T, true>
|
||||
{
|
||||
typedef const T param_type;
|
||||
};
|
||||
|
||||
template <typename T, bool isp, bool b1>
|
||||
struct ct_imp
|
||||
{
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
template <typename T, bool isp>
|
||||
struct ct_imp<T, isp, true, true>
|
||||
struct ct_imp<T, isp, true>
|
||||
{
|
||||
typedef T const param_type;
|
||||
typedef typename ct_imp2<T, sizeof(T) <= sizeof(void*)>::param_type param_type;
|
||||
};
|
||||
|
||||
template <typename T, bool b1, bool b2>
|
||||
struct ct_imp<T, true, b1, b2>
|
||||
template <typename T, bool b1>
|
||||
struct ct_imp<T, true, b1>
|
||||
{
|
||||
typedef T const param_type;
|
||||
};
|
||||
@ -64,7 +76,11 @@ public:
|
||||
// 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;
|
||||
typedef typename boost::detail::ct_imp<
|
||||
T,
|
||||
::boost::is_pointer<T>::value,
|
||||
::boost::is_arithmetic<T>::value
|
||||
>::param_type param_type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -76,7 +92,7 @@ struct call_traits<T&>
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
|
||||
#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x551)
|
||||
#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x570 ) )
|
||||
// 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
|
||||
@ -106,7 +122,7 @@ struct call_traits<T&const volatile>
|
||||
typedef T& param_type; // hh removed const
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS)
|
||||
template <typename T, std::size_t N>
|
||||
struct call_traits<T [N]>
|
||||
{
|
||||
@ -132,6 +148,7 @@ public:
|
||||
typedef const array_type& const_reference;
|
||||
typedef const T* const param_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,16 @@
|
||||
// (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.
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// See http://www.boost.org/libs/utility for most recent version including documentation.
|
||||
|
||||
// compressed_pair: pair that "compresses" empty members
|
||||
// (see libs/utility/compressed_pair.htm)
|
||||
//
|
||||
// JM changes 25 Jan 2004:
|
||||
// For the case where T1 == T2 and both are empty, then first() and second()
|
||||
// should return different objects.
|
||||
// JM changes 25 Jan 2000:
|
||||
// Removed default arguments from compressed_pair_switch to get
|
||||
// C++ Builder 4 to accept them
|
||||
@ -19,16 +21,19 @@
|
||||
#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/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_empty.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair;
|
||||
|
||||
|
||||
// compressed_pair
|
||||
|
||||
namespace details
|
||||
@ -75,7 +80,9 @@ namespace details
|
||||
template <typename T>
|
||||
inline void cp_swap(T& t1, T& t2)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
using std::swap;
|
||||
#endif
|
||||
swap(t1, t2);
|
||||
}
|
||||
|
||||
@ -99,10 +106,10 @@ namespace details
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
@ -111,10 +118,10 @@ namespace details
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
void swap(::boost::compressed_pair<T1, T2>& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
cp_swap(first_, y.first());
|
||||
cp_swap(second_, y.second());
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
@ -125,7 +132,7 @@ namespace details
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 1>
|
||||
: private T1
|
||||
: private ::boost::remove_cv<T1>::type
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
@ -142,10 +149,10 @@ namespace details
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
@ -154,10 +161,10 @@ namespace details
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
void swap(::boost::compressed_pair<T1,T2>& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(second_, y.second_);
|
||||
cp_swap(second_, y.second());
|
||||
}
|
||||
private:
|
||||
second_type second_;
|
||||
@ -167,7 +174,7 @@ namespace details
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 2>
|
||||
: private T2
|
||||
: private ::boost::remove_cv<T2>::type
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
@ -184,10 +191,10 @@ namespace details
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: second_type(y), first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
@ -196,10 +203,10 @@ namespace details
|
||||
second_reference second() {return *this;}
|
||||
second_const_reference second() const {return *this;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
void swap(::boost::compressed_pair<T1,T2>& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(first_, y.first());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -210,8 +217,8 @@ namespace details
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 3>
|
||||
: private T1,
|
||||
private T2
|
||||
: private ::boost::remove_cv<T1>::type,
|
||||
private ::boost::remove_cv<T2>::type
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
@ -228,10 +235,10 @@ namespace details
|
||||
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)
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
@ -241,7 +248,7 @@ namespace details
|
||||
second_const_reference second() const {return *this;}
|
||||
//
|
||||
// no need to swap empty bases:
|
||||
void swap(compressed_pair_imp&) {}
|
||||
void swap(::boost::compressed_pair<T1,T2>&) {}
|
||||
};
|
||||
|
||||
// JM
|
||||
@ -250,7 +257,7 @@ namespace details
|
||||
// but reuses T1 base class for both first() and second().
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 4>
|
||||
: private T1
|
||||
: private ::boost::remove_cv<T1>::type
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
@ -264,20 +271,21 @@ namespace details
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type)
|
||||
: first_type(x) {}
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), m_second(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_type(x), m_second(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;}
|
||||
second_reference second() {return m_second;}
|
||||
second_const_reference second() const {return m_second;}
|
||||
|
||||
void swap(compressed_pair_imp&) {}
|
||||
void swap(::boost::compressed_pair<T1,T2>&) {}
|
||||
private:
|
||||
T2 m_second;
|
||||
};
|
||||
|
||||
// 5 T1 == T2 and are not empty: //JM
|
||||
@ -300,7 +308,7 @@ namespace details
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
compressed_pair_imp(first_param_type x)
|
||||
: first_(x), second_(x) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
@ -309,10 +317,10 @@ namespace details
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp<T1, T2, 5>& y)
|
||||
void swap(::boost::compressed_pair<T1, T2>& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
cp_swap(first_, y.first());
|
||||
cp_swap(second_, y.second());
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
@ -396,7 +404,10 @@ public:
|
||||
|
||||
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) {}
|
||||
#if !(defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530))
|
||||
explicit
|
||||
#endif
|
||||
compressed_pair(first_param_type x) : base(x) {}
|
||||
|
||||
first_reference first() {return base::first();}
|
||||
first_const_reference first() const {return base::first();}
|
||||
@ -404,7 +415,7 @@ public:
|
||||
second_reference second() {return base::second();}
|
||||
second_const_reference second() const {return base::second();}
|
||||
|
||||
void swap(compressed_pair& y) { base::swap(y); }
|
||||
void swap(::boost::compressed_pair<T,T>& y) { base::swap(y); }
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
@ -419,4 +430,3 @@ swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
|
||||
#endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
|
||||
|
||||
|
@ -1,14 +1,21 @@
|
||||
// (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.
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// See http://www.boost.org/libs/utility for most recent version including documentation.
|
||||
//
|
||||
// Crippled version for crippled compilers:
|
||||
// see libs/utility/call_traits.htm
|
||||
//
|
||||
|
||||
/* Release notes:
|
||||
01st October 2000:
|
||||
Fixed call_traits on VC6, using "poor man's partial specialisation",
|
||||
using ideas taken from "Generative programming" by Krzysztof Czarnecki
|
||||
& Ulrich Eisenecker.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_OB_CALL_TRAITS_HPP
|
||||
#define BOOST_OB_CALL_TRAITS_HPP
|
||||
|
||||
@ -16,12 +23,135 @@
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#ifndef BOOST_ARITHMETIC_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/arithmetic_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_COMPOSITE_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/composite_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
//
|
||||
// use member templates to emulate
|
||||
// partial specialisation:
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
struct standard_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T& param_type;
|
||||
};
|
||||
template <class T>
|
||||
struct simple_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T param_type;
|
||||
};
|
||||
template <class T>
|
||||
struct reference_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T reference;
|
||||
typedef T const_reference;
|
||||
typedef T param_type;
|
||||
};
|
||||
|
||||
template <bool pointer, bool arithmetic, bool reference>
|
||||
struct call_traits_chooser
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef standard_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_traits_chooser<true, false, false>
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef simple_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_traits_chooser<false, false, true>
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef reference_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <bool size_is_small>
|
||||
struct call_traits_sizeof_chooser2
|
||||
{
|
||||
template <class T>
|
||||
struct small_rebind
|
||||
{
|
||||
typedef simple_call_traits<T> small_type;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct call_traits_sizeof_chooser2<false>
|
||||
{
|
||||
template <class T>
|
||||
struct small_rebind
|
||||
{
|
||||
typedef standard_call_traits<T> small_type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_traits_chooser<false, true, false>
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
enum { sizeof_choice = (sizeof(T) <= sizeof(void*)) };
|
||||
typedef call_traits_sizeof_chooser2<(sizeof(T) <= sizeof(void*))> chooser;
|
||||
typedef typename chooser::template small_rebind<T> bound_type;
|
||||
typedef typename bound_type::small_type type;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
private:
|
||||
typedef detail::call_traits_chooser<
|
||||
::boost::is_pointer<T>::value,
|
||||
::boost::is_arithmetic<T>::value,
|
||||
::boost::is_reference<T>::value
|
||||
> chooser;
|
||||
typedef typename chooser::template rebind<T> bound_type;
|
||||
typedef typename bound_type::type call_traits_type;
|
||||
public:
|
||||
typedef typename call_traits_type::value_type value_type;
|
||||
typedef typename call_traits_type::reference reference;
|
||||
typedef typename call_traits_type::const_reference const_reference;
|
||||
typedef typename call_traits_type::param_type param_type;
|
||||
};
|
||||
|
||||
#else
|
||||
//
|
||||
// sorry call_traits is completely non-functional
|
||||
// blame your broken compiler:
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
@ -31,6 +161,8 @@ struct call_traits
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
#endif // member templates
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_OB_CALL_TRAITS_HPP
|
||||
|
@ -1,13 +1,18 @@
|
||||
// (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.
|
||||
// Use, modification and distribution are subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// See http://www.boost.org/libs/utility for most recent version including documentation.
|
||||
// see libs/utility/compressed_pair.hpp
|
||||
//
|
||||
/* Release notes:
|
||||
20 Jan 2001:
|
||||
Fixed obvious bugs (David Abrahams)
|
||||
07 Oct 2000:
|
||||
Added better single argument constructor support.
|
||||
03 Oct 2000:
|
||||
Added VC6 support (JM).
|
||||
23rd July 2000:
|
||||
Additional comments added. (JM)
|
||||
Jan 2000:
|
||||
@ -20,8 +25,11 @@
|
||||
#define BOOST_OB_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef BOOST_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits.hpp>
|
||||
#ifndef BOOST_OBJECT_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/object_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_SAME_TRAITS_HPP
|
||||
#include <boost/type_traits/same_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_CALL_TRAITS_HPP
|
||||
#include <boost/call_traits.hpp>
|
||||
@ -29,6 +37,426 @@
|
||||
|
||||
namespace boost
|
||||
{
|
||||
#ifdef BOOST_MSVC6_MEMBER_TEMPLATES
|
||||
//
|
||||
// use member templates to emulate
|
||||
// partial specialisation. Note that due to
|
||||
// problems with overload resolution with VC6
|
||||
// each of the compressed_pair versions that follow
|
||||
// have one template single-argument constructor
|
||||
// in place of two specific constructors:
|
||||
//
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair;
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class A, class T1, class T2>
|
||||
struct best_conversion_traits
|
||||
{
|
||||
typedef char one;
|
||||
typedef char (&two)[2];
|
||||
static A a;
|
||||
static one test(T1);
|
||||
static two test(T2);
|
||||
|
||||
enum { value = sizeof(test(a)) };
|
||||
};
|
||||
|
||||
template <int>
|
||||
struct init_one;
|
||||
|
||||
template <>
|
||||
struct init_one<1>
|
||||
{
|
||||
template <class A, class T1, class T2>
|
||||
static void init(const A& a, T1* p1, T2*)
|
||||
{
|
||||
*p1 = a;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct init_one<2>
|
||||
{
|
||||
template <class A, class T1, class T2>
|
||||
static void init(const A& a, T1*, T2* p2)
|
||||
{
|
||||
*p2 = a;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// T1 != T2, both non-empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_0
|
||||
{
|
||||
private:
|
||||
T1 _first;
|
||||
T2 _second;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_0() : _first(), _second() {}
|
||||
compressed_pair_0(first_param_type x, second_param_type y) : _first(x), _second(y) {}
|
||||
template <class A>
|
||||
explicit compressed_pair_0(const A& val)
|
||||
{
|
||||
init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, &_second);
|
||||
}
|
||||
compressed_pair_0(const ::boost::compressed_pair<T1,T2>& x)
|
||||
: _first(x.first()), _second(x.second()) {}
|
||||
|
||||
#if 0
|
||||
compressed_pair_0& operator=(const compressed_pair_0& x) {
|
||||
cout << "assigning compressed pair 0" << endl;
|
||||
_first = x._first;
|
||||
_second = x._second;
|
||||
cout << "finished assigning compressed pair 0" << endl;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
first_reference first() { return _first; }
|
||||
first_const_reference first() const { return _first; }
|
||||
|
||||
second_reference second() { return _second; }
|
||||
second_const_reference second() const { return _second; }
|
||||
|
||||
void swap(compressed_pair_0& y)
|
||||
{
|
||||
using std::swap;
|
||||
swap(_first, y._first);
|
||||
swap(_second, y._second);
|
||||
}
|
||||
};
|
||||
|
||||
// T1 != T2, T2 empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_1 : T2
|
||||
{
|
||||
private:
|
||||
T1 _first;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_1() : T2(), _first() {}
|
||||
compressed_pair_1(first_param_type x, second_param_type y) : T2(y), _first(x) {}
|
||||
|
||||
template <class A>
|
||||
explicit compressed_pair_1(const A& val)
|
||||
{
|
||||
init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this));
|
||||
}
|
||||
|
||||
compressed_pair_1(const ::boost::compressed_pair<T1,T2>& x)
|
||||
: T2(x.second()), _first(x.first()) {}
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
|
||||
// Total weirdness. If the assignment to _first is moved after
|
||||
// the call to the inherited operator=, then this breaks graph/test/graph.cpp
|
||||
// by way of iterator_adaptor.
|
||||
compressed_pair_1& operator=(const compressed_pair_1& x) {
|
||||
_first = x._first;
|
||||
T2::operator=(x);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
first_reference first() { return _first; }
|
||||
first_const_reference first() const { return _first; }
|
||||
|
||||
second_reference second() { return *this; }
|
||||
second_const_reference second() const { return *this; }
|
||||
|
||||
void swap(compressed_pair_1& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
using std::swap;
|
||||
swap(_first, y._first);
|
||||
}
|
||||
};
|
||||
|
||||
// T1 != T2, T1 empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_2 : T1
|
||||
{
|
||||
private:
|
||||
T2 _second;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_2() : T1(), _second() {}
|
||||
compressed_pair_2(first_param_type x, second_param_type y) : T1(x), _second(y) {}
|
||||
template <class A>
|
||||
explicit compressed_pair_2(const A& val)
|
||||
{
|
||||
init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second);
|
||||
}
|
||||
compressed_pair_2(const ::boost::compressed_pair<T1,T2>& x)
|
||||
: T1(x.first()), _second(x.second()) {}
|
||||
|
||||
#if 0
|
||||
compressed_pair_2& operator=(const compressed_pair_2& x) {
|
||||
cout << "assigning compressed pair 2" << endl;
|
||||
T1::operator=(x);
|
||||
_second = x._second;
|
||||
cout << "finished assigning compressed pair 2" << endl;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
first_reference first() { return *this; }
|
||||
first_const_reference first() const { return *this; }
|
||||
|
||||
second_reference second() { return _second; }
|
||||
second_const_reference second() const { return _second; }
|
||||
|
||||
void swap(compressed_pair_2& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
using std::swap;
|
||||
swap(_second, y._second);
|
||||
}
|
||||
};
|
||||
|
||||
// T1 != T2, both empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_3 : T1, T2
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_3() : T1(), T2() {}
|
||||
compressed_pair_3(first_param_type x, second_param_type y) : T1(x), T2(y) {}
|
||||
template <class A>
|
||||
explicit compressed_pair_3(const A& val)
|
||||
{
|
||||
init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this));
|
||||
}
|
||||
compressed_pair_3(const ::boost::compressed_pair<T1,T2>& x)
|
||||
: T1(x.first()), T2(x.second()) {}
|
||||
|
||||
first_reference first() { return *this; }
|
||||
first_const_reference first() const { return *this; }
|
||||
|
||||
second_reference second() { return *this; }
|
||||
second_const_reference second() const { return *this; }
|
||||
|
||||
void swap(compressed_pair_3& y)
|
||||
{
|
||||
// no need to swap empty base classes:
|
||||
}
|
||||
};
|
||||
|
||||
// T1 == T2, and empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_4 : T1
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_4() : T1() {}
|
||||
compressed_pair_4(first_param_type x, second_param_type y) : T1(x), m_second(y) {}
|
||||
// only one single argument constructor since T1 == T2
|
||||
explicit compressed_pair_4(first_param_type x) : T1(x), m_second(x) {}
|
||||
compressed_pair_4(const ::boost::compressed_pair<T1,T2>& x)
|
||||
: T1(x.first()), m_second(x.second()) {}
|
||||
|
||||
first_reference first() { return *this; }
|
||||
first_const_reference first() const { return *this; }
|
||||
|
||||
second_reference second() { return m_second; }
|
||||
second_const_reference second() const { return m_second; }
|
||||
|
||||
void swap(compressed_pair_4& y)
|
||||
{
|
||||
// no need to swap empty base classes:
|
||||
}
|
||||
private:
|
||||
T2 m_second;
|
||||
};
|
||||
|
||||
// T1 == T2, not empty
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_5
|
||||
{
|
||||
private:
|
||||
T1 _first;
|
||||
T2 _second;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_5() : _first(), _second() {}
|
||||
compressed_pair_5(first_param_type x, second_param_type y) : _first(x), _second(y) {}
|
||||
// only one single argument constructor since T1 == T2
|
||||
explicit compressed_pair_5(first_param_type x) : _first(x), _second(x) {}
|
||||
compressed_pair_5(const ::boost::compressed_pair<T1,T2>& c)
|
||||
: _first(c.first()), _second(c.second()) {}
|
||||
|
||||
first_reference first() { return _first; }
|
||||
first_const_reference first() const { return _first; }
|
||||
|
||||
second_reference second() { return _second; }
|
||||
second_const_reference second() const { return _second; }
|
||||
|
||||
void swap(compressed_pair_5& y)
|
||||
{
|
||||
using std::swap;
|
||||
swap(_first, y._first);
|
||||
swap(_second, y._second);
|
||||
}
|
||||
};
|
||||
|
||||
template <bool e1, bool e2, bool same>
|
||||
struct compressed_pair_chooser
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_0<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct compressed_pair_chooser<false, true, false>
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_1<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct compressed_pair_chooser<true, false, false>
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_2<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct compressed_pair_chooser<true, true, false>
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_3<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct compressed_pair_chooser<true, true, true>
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_4<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct compressed_pair_chooser<false, false, true>
|
||||
{
|
||||
template <class T1, class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef compressed_pair_5<T1, T2> type;
|
||||
};
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_traits
|
||||
{
|
||||
private:
|
||||
typedef compressed_pair_chooser<is_empty<T1>::value, is_empty<T2>::value, is_same<T1,T2>::value> chooser;
|
||||
typedef typename chooser::template rebind<T1, T2> bound_type;
|
||||
public:
|
||||
typedef typename bound_type::type type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair : public detail::compressed_pair_traits<T1, T2>::type
|
||||
{
|
||||
private:
|
||||
typedef typename detail::compressed_pair_traits<T1, T2>::type base_type;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair() : base_type() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : base_type(x, y) {}
|
||||
template <class A>
|
||||
explicit compressed_pair(const A& x) : base_type(x){}
|
||||
|
||||
first_reference first() { return base_type::first(); }
|
||||
first_const_reference first() const { return base_type::first(); }
|
||||
|
||||
second_reference second() { return base_type::second(); }
|
||||
second_const_reference second() const { return base_type::second(); }
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
#else
|
||||
// no partial specialisation, no member templates:
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair
|
||||
@ -72,7 +500,11 @@ inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_OB_COMPRESSED_PAIR_HPP
|
||||
|
||||
|
||||
|
||||
|
@ -1,563 +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
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning( disable : 4284 ) // complaint about return type of
|
||||
#endif // operator-> not begin a UDT
|
||||
|
||||
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,96 +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
|
||||
#include <utility> // for std::pair
|
||||
|
||||
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
|
||||
|
||||
// class tied -------------------------------------------------------//
|
||||
|
||||
// A helper for conveniently assigning the two values from a pair
|
||||
// into separate variables. The idea for this comes from Jaakko J<>rvi's
|
||||
// Binder/Lambda Library.
|
||||
|
||||
// Constributed by Jeremy Siek
|
||||
|
||||
template <class A, class B>
|
||||
class tied {
|
||||
public:
|
||||
inline tied(A& a, B& b) : _a(a), _b(b) { }
|
||||
template <class U, class V>
|
||||
inline tied& operator=(const std::pair<U,V>& p) {
|
||||
_a = p.first;
|
||||
_b = p.second;
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
A& _a;
|
||||
B& _b;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
inline tied<A,B> tie(A& a, B& b) { return tied<A,B>(a, b); }
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UTILITY_HPP
|
||||
|
72
index.htm
72
index.htm
@ -1,72 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>Boost Utility Library</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<table border="1" cellpadding="2" bgcolor="#007F7F">
|
||||
<tr>
|
||||
<td bgcolor="#FFFFFF"><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277" height="86"></td>
|
||||
<td><a href="../../index.htm"><font color="#FFFFFF" size="4" face="Arial">Home</font></a></td>
|
||||
<td><a href="../../libraries.htm"><font color="#FFFFFF" size="4" face="Arial">Libraries</font></a></td>
|
||||
<td><a href="../../people.htm"><font color="#FFFFFF" size="4" face="Arial">People</font></a></td>
|
||||
<td><a href="../../more/faq.htm"><font color="#FFFFFF" size="4" face="Arial">FAQ</font></a></td>
|
||||
<td><a href="../../more/index.htm"><font color="#FFFFFF" size="4" face="Arial">More</font></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h1>Boost Utility Library</h1>
|
||||
<table border="1" cellpadding="5">
|
||||
<tr>
|
||||
<td><b><i>Header</i></b></td>
|
||||
<td><b><i>Contents</i></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/utility.hpp"><code>boost/utility.hpp<br>
|
||||
</code></a><a href="utility.htm">[Documentation]</a></td>
|
||||
<td>Class <b>noncopyable</b> plus <b>next()</b> and <b>prior()</b> template
|
||||
functions.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/cast.hpp"><code>boost/cast.hpp</code></a><br>
|
||||
<a href="cast.htm">[Documentation]</a></td>
|
||||
<td><b>polymorphic_cast</b>, <b>implicit_cast</b>, and <b>numeric_cast</b>
|
||||
function templates.
|
||||
<p><i>[Beta.]</i></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/operators.hpp">boost/operators.hpp</a><br>
|
||||
<a href="operators.htm">[Documentation]</a></td>
|
||||
<td>Templates <b>equality_comparable</b>, <b>less_than_comparable</b>, <b>addable</b>,
|
||||
and the like ease the task of defining comparison and arithmetic
|
||||
operators, and iterators.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a><br>
|
||||
[<a href="type_traits.htm">Documentation</a>]</td>
|
||||
<td>Template classes that describe the fundamental properties of a type. [<a href="c++_type_traits.htm">DDJ
|
||||
Article "C++ type traits"</a>]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/detail/call_traits.hpp">boost/call_traits.hpp</a><br>
|
||||
[<a href="call_traits.htm">Documentation</a>]</td>
|
||||
<td>Template class call_traits<T>, that defines types used for passing
|
||||
parameters to and from a proceedure.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../../boost/detail/compressed_pair.hpp">boost/compressed_pair.hpp</a><br>
|
||||
[<a href="compressed_pair.htm">Documentation</a>]</td>
|
||||
<td>Template class compressed_pait<T1, T2> which pairs two values
|
||||
using the empty member optimisation where appropriate.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->27 July 2000<!--webbot bot="Timestamp" endspan i-checksum="18770" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,45 +0,0 @@
|
||||
// (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>
|
||||
|
||||
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.
|
||||
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
typedef std::binder1st< std::multiplies<int> > Function;
|
||||
typedef boost::transform_iterator<Function, int*,
|
||||
boost::iterator<std::random_access_iterator_tag, int>
|
||||
>::type doubling_iterator;
|
||||
|
||||
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
|
||||
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
while (i != i_end)
|
||||
std::cout << *i++ << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
// Here is an example of counting from 0 to 5 using the integer_range class.
|
||||
|
||||
boost::integer_range<int> r(0,5);
|
||||
|
||||
std::cout << "counting to from 0 to 4:" << std::endl;
|
||||
std::copy(r.begin(), r.end(), std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,629 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>Header boost/iterator_adaptors.hpp Documentation</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||
align="center" width="277" height="86">
|
||||
|
||||
<h1>Header
|
||||
<a href="../../boost/pending/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a></h1>
|
||||
|
||||
<p>The file <tt>boost/iterator_adaptors.hpp</tt>
|
||||
includes the main <tt>iterator_adaptors</tt> class and several other classes
|
||||
for constructing commonly used iterator adaptors.</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="#iterator_adaptors"><tt>iterator_adaptors</tt></a>.
|
||||
<li><a href="#iterator_adaptor"><tt>iterator_adaptor</tt></a>.
|
||||
<li><a href="#transform_iterator"><tt>transform_iterator</tt></a>
|
||||
<li><a href="#indirect_iterators"><tt>indirect_iterators</tt></a>
|
||||
<li><a href="#reverse_iterators"><tt>reverse_iterators</tt></a>
|
||||
<li><a href="#integer_range"><tt>integer_range</tt></a>
|
||||
</ul>
|
||||
|
||||
|
||||
<!-- put in something about Andrei Alexandrescu's contribution? -->
|
||||
|
||||
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
|
||||
Abrahams</a> started the library, coming up with the idea to use
|
||||
policy classes and how to handle the const/non-const iterator
|
||||
interactions. He also contributed the <tt>indirect_iterators</tt> and
|
||||
<tt>reverse_iterators</tt> classes.<br>
|
||||
|
||||
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||
contributed <tt>transform_iterator</tt>, <tt>integer_range</tt>,
|
||||
and this documentation.
|
||||
|
||||
<h3><a name="iterator_adaptors">The Iterator Adaptors Class</a></h3>
|
||||
|
||||
Implementing standard conforming iterators is a non-trivial task.
|
||||
There are some fine-points such as iterator/const_iterator
|
||||
interactions and there are the myriad of operators that should be
|
||||
implemented but are easily forgotten such as
|
||||
<tt>operator->()</tt>. The purpose of the
|
||||
<tt>iterator_adaptors</tt> class is to make it easier to implement an
|
||||
iterator class, and even easier to extend and adapt existing iterator
|
||||
types. The <tt>iterator_adaptors</tt> class itself is not an adaptor
|
||||
class but a <i>type generator</i>. It generates a pair of adaptor classes,
|
||||
one class for the mutable iterator and one class for the const
|
||||
iterator. The definition of the <tt>iterator_adaptors</tt> class is as
|
||||
follows:
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class Iterator,
|
||||
class ConstIterator,
|
||||
class Traits = std::iterator_traits<Iterator>,
|
||||
class ConstTraits = std::iterator_traits<ConstIterator>,
|
||||
class Policies = default_iterator_policies>
|
||||
struct iterator_adaptors
|
||||
{
|
||||
typedef ... iterator;
|
||||
typedef ... const_iterator;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<p>The <tt>Iterator</tt> and <tt>ConstIterator</tt> template parameters
|
||||
are the iterator types that you want to adapt. The <tt>Traits</tt> and
|
||||
<tt>ConstTraits</tt> must be iterator traits classes. The traits
|
||||
parameters default to the specialization of the
|
||||
<tt>std::iterator_traits</tt> class for the adapted iterators. If you
|
||||
want the traits for your new iterator adaptor (<tt>value_type</tt>,
|
||||
<tt>iterator_category</tt>, etc.) to be the same as the adapted
|
||||
iterator then use the default, otherwise create your own traits
|
||||
classes and pass them in <a href="#1">[1]</a>.
|
||||
|
||||
|
||||
<p>The <tt>Policies</tt> class that you pass in will become the heart of
|
||||
the iterator adaptor. The policy class determines how your new adaptor
|
||||
class will behave. The <tt>Policies</tt> class must implement 3, 4, or
|
||||
7 of the core iterator operations depending on whether you wish the
|
||||
new iterator adaptor class to be a
|
||||
<a href="http://www.sgi.com/Technology/STL/ForwardIterator.html">
|
||||
ForwardIterator</a>,
|
||||
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
|
||||
BidirectionalIterator</a>, or <a
|
||||
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||
RandomAccessIterator</a>. Make sure that the
|
||||
<tt>iterator_category</tt> type of the traits class you pass in
|
||||
matches the category of iterator that you want to create. The default
|
||||
policy class, <tt>default_iterator_policies</tt>, implements all 7 of
|
||||
the core operations in the usual way. If you wish to create an
|
||||
iterator adaptor that only changes a few of the iterator's behaviors,
|
||||
then you can have your new policy class inherit from
|
||||
<tt>default_iterator_policies</tt> to avoid retyping the usual
|
||||
behaviours. You should also look at <tt>default_iterator_policies</tt>
|
||||
as the "boiler-plate" for your own policy classes. The
|
||||
following is definition of the <tt>default_iterator_policies</tt>
|
||||
class:
|
||||
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
struct default_iterator_policies
|
||||
{
|
||||
// required for a ForwardIterator
|
||||
template <class Reference, class Iterator>
|
||||
Reference dereference(type<Reference>, const Iterator& x) const
|
||||
{ return *x; }
|
||||
|
||||
template <class Iterator>
|
||||
void increment(Iterator& x) const
|
||||
{ ++x; }
|
||||
|
||||
template <class Iterator1, class Iterator2>
|
||||
bool equal(Iterator1& x, Iterator2& y) const
|
||||
{ return x == y; }
|
||||
|
||||
// required for a BidirectionalIterator
|
||||
template <class Iterator>
|
||||
void decrement(Iterator& x) const
|
||||
{ --x; }
|
||||
|
||||
// required for a RandomAccessIterator
|
||||
template <class Iterator, class DifferenceType>
|
||||
void advance(Iterator& x, DifferenceType n) const
|
||||
{ x += n; }
|
||||
|
||||
template <class Difference, class Iterator1, class Iterator2>
|
||||
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||
{ return y - x; }
|
||||
|
||||
template <class Iterator1, class Iterator2>
|
||||
bool less(Iterator1& x, Iterator2& y) const
|
||||
{ return x < y; }
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<p>
|
||||
The generated iterator adaptor types will have the following
|
||||
constructors.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
<i>iterator</i>(const Iterator& i, const Policies& p = Policies())
|
||||
|
||||
<i>const_iterator</i>(const ConstIterator& i, const Policies& p = Policies())
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<h3><a name="iterator_adaptor">The Iterator Adaptor Class</a></h3>
|
||||
|
||||
This is the class used inside of the <tt>iterator_adaptors</tt> type
|
||||
generator. Use this class directly (instead of using
|
||||
<tt>iterator_adaptors</tt>) when there is no difference between the
|
||||
const and non-const versions of the iterator type. Often this is
|
||||
because there is only a const (read-only) version of the iterator, as
|
||||
is the case for <tt>std::set</tt>'s iterators. Use the same type for
|
||||
the <tt>Iterator</tt> and <tt>NonconstIterator</tt> template
|
||||
arguments.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class Iterator,
|
||||
class Policies = default_iterator_policies,
|
||||
class NonconstIterator = Iterator,
|
||||
class Traits = std::iterator_traits<Iterator> >
|
||||
struct iterator_adaptor;
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
|
||||
<p>
|
||||
Next we will look at some iterator adaptors that are examples of how
|
||||
to use the iterator adaptors class, and that are useful iterator
|
||||
adaptors in their own right.
|
||||
|
||||
<h3><a name="transform_iterator">The Transform Iterator Class</a></h3>
|
||||
|
||||
It is often useful to automatically apply some function to the value
|
||||
returned by dereferencing (<tt>operator*()</tt>) an iterator. The
|
||||
<tt>transform_iterators</tt> class makes it easy to create an iterator
|
||||
adaptor that does just that.
|
||||
|
||||
First let us consider what the <tt>Policies</tt> class for the transform
|
||||
iterator should look like. We are only changing one of the iterator
|
||||
behaviours, so we will inherit from
|
||||
<tt>default_iterator_policies</tt>. In addition, we will need a
|
||||
function object to apply, so we will have a template parameter and a
|
||||
data member for the function object. The function will take one
|
||||
argument (the dereferenced value) and we will need to know the
|
||||
<tt>result_type</tt> of the function, so <a
|
||||
href="http://www.sgi.com/Technology/STL/AdaptableUnaryFunction.html">
|
||||
AdaptableUnaryFunction</a> is the corrent concept to choose for the
|
||||
function object type. Now for the heart of our iterator adaptor, we
|
||||
implement the <tt>dereference</tt> method, applying the function
|
||||
object to <tt>*i</tt>. The <tt>type<Reference></tt> class is
|
||||
there to tell you what the reference type of the iterator is, which is
|
||||
handy when writing generic iterator adaptors such as this one <a
|
||||
href="#2">[2]</a>.
|
||||
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class AdaptableUnaryFunction>
|
||||
struct transform_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
|
||||
|
||||
template <class Reference, class Iterator>
|
||||
Reference dereference(type<Reference>, const Iterator& i) const
|
||||
{ return m_f(*i); }
|
||||
|
||||
AdaptableUnaryFunction m_f;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
Next we need to create the traits class for our new iterator. In some
|
||||
situations you may need to create a separate traits class for the
|
||||
const and non-const iterator types, but here a single traits class
|
||||
will do. The <tt>value_type</tt> and <tt>reference</tt> type of our
|
||||
transform iterator will be the <tt>result_type</tt> of the function
|
||||
object. The <tt>difference_type</tt> and <tt>iterator_category</tt>
|
||||
will be the same as the adapted iterator.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class AdaptableUnaryFunction, class IteratorTraits>
|
||||
struct transform_iterator_traits {
|
||||
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||
typedef value_type reference;
|
||||
typedef value_type* pointer;
|
||||
typedef typename IteratorTraits::difference_type difference_type;
|
||||
typedef typename IteratorTraits::iterator_category iterator_category;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
The final step is to use the <tt>iterator_adaptor</tt> class to
|
||||
construct our transform iterator. We will use the single iterator
|
||||
adaptor version because we will not need to create both a mutable and
|
||||
const version of the transform iterator. The transform iterator is
|
||||
inherently a read-only iterator. The nicest way to package up our new
|
||||
transform iterator is to create a type generator similar to
|
||||
<tt>iterator_adaptor</tt>. The first template parameter will be the
|
||||
type of the function object. The second parameter will be the adapted
|
||||
iterator type. The third parameter is the trait class for
|
||||
the adapted iterator. Inside the <tt>transform_iterators</tt> class
|
||||
we use the <tt>transform_iterator_traits</tt> class defined above to
|
||||
create the traits class for the new transform iterator. We then use
|
||||
the <tt>iterator_adaptor</tt> class to extract the generated
|
||||
iterator adaptor type.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class AdaptableUnaryFunction,
|
||||
class Iterator,
|
||||
class Traits = std::iterator_traits<Iterator>
|
||||
>
|
||||
struct transform_iterator
|
||||
{
|
||||
typedef transform_iterator_traits<AdaptableUnaryFunction,Traits>
|
||||
TransTraits;
|
||||
typedef iterator_adaptor<Iterator, TransTraits,
|
||||
transform_iterator_policies<AdaptableUnaryFunction> >::type type;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<p>
|
||||
The following is a simple example of how to use the
|
||||
<tt>transform_iterators</tt> class to iterate through a range of
|
||||
numbers, multiplying each of them by 2 when they are dereferenced.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
typedef std::binder1st< std::multiplies<int> > Function;
|
||||
typedef boost::transform_iterator<Function, int*,
|
||||
boost::iterator<std::random_access_iterator_tag, int>
|
||||
>::type doubling_iterator;
|
||||
|
||||
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
|
||||
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
while (i != i_end)
|
||||
std::cout << *i++ << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
|
||||
<h3><a name="indirect_iterators">The Indirect Iterators Class</a></h3>
|
||||
|
||||
It is not all that uncommon to create data structures that consist of
|
||||
pointers to pointers. For such a structure it might be nice to have an
|
||||
iterator that applies a double-dereference inside the
|
||||
<tt>operator*()</tt>. The implementation of this is similar to the
|
||||
<tt>transform_iterators</tt><a href="#3">[3]</a>. We first create a
|
||||
policies class which does a double-dereference in the
|
||||
<tt>dereference()</tt> method. We then create a traits class, this
|
||||
time also including a template parameter for the traits of the second
|
||||
level iterators as well as the first. Lastly we wrap this up in the
|
||||
type generator <tt>indirect_iterators</tt>, using
|
||||
<tt>iterator_adaptors</tt> to do most of the work.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
struct indirect_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
template <class Reference, class Iterator>
|
||||
Reference dereference(type<Reference>, const Iterator& x) const
|
||||
{ return **x; }
|
||||
};
|
||||
|
||||
template <class IndirectIterator,
|
||||
class IndirectTraits = std::iterator_traits<IndirectIterator>,
|
||||
class Traits =
|
||||
std::iterator_traits<typename IndirectTraits::value_type>
|
||||
>
|
||||
struct indirect_traits
|
||||
{
|
||||
typedef typename IndirectTraits::difference_type difference_type;
|
||||
typedef typename Traits::value_type value_type;
|
||||
typedef typename Traits::pointer pointer;
|
||||
typedef typename Traits::reference reference;
|
||||
typedef typename IndirectTraits::iterator_category iterator_category;
|
||||
};
|
||||
|
||||
template <class IndirectIterator, class ConstIndirectIterator,
|
||||
class IndirectTraits =
|
||||
std::iterator_traits<IndirectIterator>,
|
||||
class ConstIndirectTraits =
|
||||
std::iterator_traits<ConstIndirectIterator>,
|
||||
class Traits =
|
||||
std::iterator_traits<typename IndirectTraits::value_type>
|
||||
>
|
||||
struct indirect_iterators
|
||||
{
|
||||
typedef typename IndirectTraits::value_type Iterator;
|
||||
typedef typename Traits::value_type ValueType;
|
||||
typedef iterator_adaptors<IndirectIterator, ConstIndirectIterator,
|
||||
indirect_traits<IndirectIterator, IndirectTraits, Traits>,
|
||||
indirect_traits<ConstIndirectIterator, ConstIndirectTraits, Traits>,
|
||||
indirect_iterator_policies
|
||||
> Adaptors;
|
||||
typedef typename Adaptors::iterator iterator;
|
||||
typedef typename Adaptors::const_iterator const_iterator;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<h3><a name="reverse_iterators">The Reverse Iterators Class</a></h3>
|
||||
|
||||
<p>
|
||||
Yes, there is already a <tt>reverse_iterator</tt> adaptor class
|
||||
defined in the C++ Standard, but using the <tt>iterator_adaptors</tt>
|
||||
class we can re-implement this classic adaptor in a more succinct and
|
||||
elegant fashion. Also, this makes for a good example of using
|
||||
<tt>iterator_adaptors</tt> that is in familiar territory.
|
||||
|
||||
<p>
|
||||
The first step is to create the <tt>Policies</tt> class. As in the
|
||||
<tt>std::reverse_iterator</tt> class, we need to flip all the
|
||||
operations of the iterator. Increment will become decrement, advancing
|
||||
by <tt>n</tt> will become retreating by <tt>n</tt>, etc.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
struct reverse_iterator_policies
|
||||
{
|
||||
template <class Reference, class Iterator>
|
||||
Reference dereference(type<Reference>, const Iterator& x) const
|
||||
{ return *boost::prior(x); }
|
||||
// this is equivalent to { Iterator tmp = x; return *--tmp; }
|
||||
|
||||
template <class Iterator>
|
||||
void increment(Iterator& x) const
|
||||
{ --x; }
|
||||
|
||||
template <class Iterator>
|
||||
void decrement(Iterator& x) const
|
||||
{ ++x; }
|
||||
|
||||
template <class Iterator, class DifferenceType>
|
||||
void advance(Iterator& x, DifferenceType n) const
|
||||
{ x -= n; }
|
||||
|
||||
template <class Difference, class Iterator1, class Iterator2>
|
||||
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||
{ return x - y; }
|
||||
|
||||
template <class Iterator1, class Iterator2>
|
||||
bool equal(Iterator1& x, Iterator2& y) const
|
||||
{ return x == y; }
|
||||
|
||||
template <class Iterator1, class Iterator2>
|
||||
bool less(Iterator1& x, Iterator2& y) const
|
||||
{ return y < x; }
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
Since the traits of the reverse iterator adaptor will be the same as
|
||||
the adapted iterator's traits, we do not need to create new traits
|
||||
classes as was the case for <tt>transform_iterator</tt>. We can skip to
|
||||
the final stage of creating a type generator class for our reverse
|
||||
iterators using the <tt>iterator_adaptor</tt> class.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class Iterator, class ConstIterator,
|
||||
class Traits = std::iterator_traits<Iterator>,
|
||||
class ConstTraits = std::iterator_traits<ConstIterator>
|
||||
>
|
||||
struct reverse_iterators
|
||||
{
|
||||
typedef iterator_adaptors<Iterator,ConstIterator,Traits,ConstTraits,
|
||||
reverse_iterator_policies> Adaptor;
|
||||
typedef typename Adaptor::iterator iterator;
|
||||
typedef typename Adaptor::const_iterator const_iterator;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
A typical use of the <tt>reverse_iterators</tt> class is in
|
||||
user-defined container types. You can use the
|
||||
<tt>reverse_iterators</tt> class to generate the reverse iterators for
|
||||
your container.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
class my_container {
|
||||
...
|
||||
typedef ... iterator;
|
||||
typedef ... const_iterator;
|
||||
|
||||
typedef reverse_iterators<iterator, const_iterator> RevIters;
|
||||
typedef typename RevIters::iterator reverse_iterator;
|
||||
typedef typename RevIters::const_iterator const_reverse_iterator;
|
||||
...
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
|
||||
<h3><a name="integer_range">The Integer Range Class</a></h3>
|
||||
|
||||
The <tt>iterator_adaptors</tt> class can not only be used for adapting
|
||||
iterators, but it can also be used to take a non-iterator type and use
|
||||
it to build an iterator. An especially simple example of this is
|
||||
turning an integer type into an iterator, a counting iterator. The
|
||||
builtin integer types of C++ are almost iterators. They have
|
||||
<tt>operator++()</tt>, <tt>operator--()</tt>, etc. The one operator
|
||||
they are lacking is the <tt>operator*()</tt>, which we will want to
|
||||
simply return the current value of the integer. The following few
|
||||
lines of code implement the policy and traits class for the counting
|
||||
iterator.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
struct counting_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
template <class IntegerType>
|
||||
IntegerType dereference(type<IntegerType>, const IntegerType& i) const
|
||||
{ return i; }
|
||||
};
|
||||
template <class IntegerType>
|
||||
struct counting_iterator_traits {
|
||||
typedef IntegerType value_type;
|
||||
typedef IntegerType reference;
|
||||
typedef value_type* pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
Typically we will want to count the integers in some range, so a nice
|
||||
interface would be to have a fake container that represents the range
|
||||
of integers. The following is the definition of such a class called
|
||||
<tt>integer_range</tt>.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
template <class IntegerType>
|
||||
struct integer_range {
|
||||
typedef typename iterator_adaptor<IntegerType,
|
||||
counting_iterator_traits<IntegerType>,
|
||||
counting_iterator_policies >::type iterator;
|
||||
typedef iterator const_iterator;
|
||||
typedef IntegerType value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef IntegerType reference;
|
||||
typedef IntegerType* pointer;
|
||||
typedef IntegerType size_type;
|
||||
|
||||
integer_range(IntegerType start, IntegerType finish)
|
||||
: m_start(start), m_finish(finish) { }
|
||||
|
||||
iterator begin() const { return iterator(m_start); }
|
||||
iterator end() const { return iterator(m_finish); }
|
||||
size_type size() const { return m_finish - m_start; }
|
||||
bool empty() const { return m_finish == m_start; }
|
||||
void swap(integer_range& x) {
|
||||
std::swap(m_start, x.m_start);
|
||||
std::swap(m_finish, x.m_finish);
|
||||
}
|
||||
protected:
|
||||
IntegerType m_start, m_finish;
|
||||
};
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<p>
|
||||
The following is an example of how to use the
|
||||
<tt>integer_range</tt> class to count from 0 to 4.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||
<PRE>
|
||||
boost::integer_range<int> r(0,5);
|
||||
|
||||
cout << "counting to from 0 to 4:" << endl;
|
||||
std::copy(r.begin(), r.end(), ostream_iterator<int>(cout, " "));
|
||||
cout << endl;
|
||||
</PRE></TD></TABLE>
|
||||
|
||||
<h3>Challenge</h3>
|
||||
|
||||
<p>
|
||||
There is an unlimited number of ways the the
|
||||
<tt>iterator_adaptors</tt> class can be used to create iterators. One
|
||||
interesting exercise would be to re-implement the iterators of
|
||||
<tt>std::list</tt> and <tt>std::slist</tt> using
|
||||
<tt>iterator_adaptors</tt>, where the adapted <tt>Iterator</tt> types
|
||||
would be node pointers.
|
||||
|
||||
|
||||
<h3>Notes</h3>
|
||||
|
||||
<p>
|
||||
<a name="1">[1]</a>
|
||||
If your compiler does not support partial specialization and hence
|
||||
does not have a working <tt>std::iterator_traits</tt> class, you will
|
||||
not be able to use the defaults and will need to supply your own
|
||||
<tt>Traits</tt> and <tt>ConstTraits</tt> classes.
|
||||
|
||||
<p>
|
||||
<a name="2">[2]</a>
|
||||
The reference type could also be obtained from
|
||||
<tt>std::iterator_traits</tt>, but that is not portable on compilers
|
||||
that do not support partial specialization.
|
||||
|
||||
<p>
|
||||
<a name="3">[3]</a>
|
||||
It would have been more elegant to implement <tt>indirect_iterators</tt>
|
||||
using <tt>transform_iterators</tt>, but for subtle reasons that would require
|
||||
the use of <tt>boost::remove_cv</tt> which is not portable.
|
||||
|
||||
<h3>Implementation Notes</h3>
|
||||
|
||||
The code is somewhat complicated because there are three iterator
|
||||
adaptor class: <tt>forward_iterator_adaptor</tt>,
|
||||
<tt>bidirectional_iterator_adaptor</tt>, and
|
||||
<tt>random_access_iterator_adaptor</tt>. The alternative would be to
|
||||
just have one iterator adaptor equivalent to the
|
||||
<tt>random_access_iterator_adaptor</tt>. The reason for going with
|
||||
the three adaptors is that according to 14.5.3p5 in the C++ Standard,
|
||||
friend functions defined inside a template class body are instantiated
|
||||
when the template class is instantiated. This means that if we only
|
||||
used the one iterator adaptor, then if the adapted iterator did not
|
||||
meet all of the requirements for a
|
||||
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||
RandomAccessIterator</a> then a compiler error should occur. Many
|
||||
current compilers in fact do not instantiate the friend functions
|
||||
unless used, so we could get away with the one iterator adaptor in
|
||||
most cases. However, out of respect for the standard this implementation
|
||||
uses the three adaptors.
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->27 Sep 2000<!--webbot bot="Timestamp" endspan i-checksum="14936" --></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>
|
@ -1,169 +0,0 @@
|
||||
// Demonstrate and test boost/operators.hpp on std::iterators --------------//
|
||||
|
||||
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
using namespace boost;
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
string array[] = { "apple", "orange", "pear", "peach", "grape", "plum" };
|
||||
{
|
||||
test_iter<string,string&,string*> i = array,
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// Tests for all of the operators added by random_access_iterator_helper
|
||||
|
||||
// test i++
|
||||
while (i != ie)
|
||||
cout << *i++ << " ";
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i--
|
||||
while (ie != i) {
|
||||
ie--;
|
||||
cout << *ie << " ";
|
||||
}
|
||||
cout << endl;
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// test i->m
|
||||
while (i != ie) {
|
||||
cout << i->size() << " ";
|
||||
++i;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i + n
|
||||
while (i < ie) {
|
||||
cout << *i << " ";
|
||||
i = i + 2;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test n + i
|
||||
while (i < ie) {
|
||||
cout << *i << " ";
|
||||
i = ptrdiff_t(2) + i;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i - n
|
||||
while (ie > i) {
|
||||
ie = ie - 2;
|
||||
cout << *ie << " ";
|
||||
}
|
||||
cout << endl;
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// test i[n]
|
||||
for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j)
|
||||
cout << i[j] << " ";
|
||||
cout << endl;
|
||||
}
|
||||
{
|
||||
test_iter<string, const string&, const string*> i = array,
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// Tests for all of the operators added by random_access_iterator_helper
|
||||
|
||||
// test i++
|
||||
while (i != ie)
|
||||
cout << *i++ << " ";
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i--
|
||||
while (ie != i) {
|
||||
ie--;
|
||||
cout << *ie << " ";
|
||||
}
|
||||
cout << endl;
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// test i->m
|
||||
while (i != ie) {
|
||||
cout << i->size() << " ";
|
||||
++i;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i + n
|
||||
while (i < ie) {
|
||||
cout << *i << " ";
|
||||
i = i + 2;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test n + i
|
||||
while (i < ie) {
|
||||
cout << *i << " ";
|
||||
i = ptrdiff_t(2) + i;
|
||||
}
|
||||
cout << endl;
|
||||
i = array;
|
||||
|
||||
// test i - n
|
||||
while (ie > i) {
|
||||
ie = ie - 2;
|
||||
cout << *ie << " ";
|
||||
}
|
||||
cout << endl;
|
||||
ie = array + sizeof(array)/sizeof(string);
|
||||
|
||||
// test i[n]
|
||||
for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j)
|
||||
cout << i[j] << " ";
|
||||
cout << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// boost class noncopyable 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
|
||||
// 9 Jun 99 Add unnamed namespace
|
||||
// 2 Jun 99 Initial Version
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <iostream>
|
||||
|
||||
// This program demonstrates compiler errors resulting from trying to copy
|
||||
// construct or copy assign a class object derived from class noncopyable.
|
||||
|
||||
namespace
|
||||
{
|
||||
class DontTreadOnMe : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
DontTreadOnMe() { std::cout << "defanged!" << std::endl; }
|
||||
}; // DontTreadOnMe
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
DontTreadOnMe object1;
|
||||
DontTreadOnMe object2(object1);
|
||||
object1 = object2;
|
||||
return 0;
|
||||
} // main
|
||||
|
597
operators.htm
597
operators.htm
@ -1,597 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>Header boost/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 -->27 Sep 2000<!--webbot bot="Timestamp" endspan i-checksum="14936" --></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>
|
@ -1,481 +0,0 @@
|
||||
// Demonstrate and test boost/operators.hpp -------------------------------//
|
||||
|
||||
// (C) Copyright Beman Dawes 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 Jun 00 Added regression test for a bug I found (David Abrahams)
|
||||
// 17 Jun 00 Fix for broken compilers (Aleksey Gurtovoy)
|
||||
// ?? ??? 00 Major update to randomly test all one- and two- argument forms by
|
||||
// wrapping integral types and comparing the results of operations to
|
||||
// the results for the raw types (David Abrahams)
|
||||
// 12 Dec 99 Minor update, output confirmation message.
|
||||
// 15 Nov 99 Initial version
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <boost/min_rand.hpp>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// avoiding a template version of true_value so as to not confuse VC++
|
||||
int true_value(int x) { return x; }
|
||||
long true_value(long x) { return x; }
|
||||
signed char true_value(signed char x) { return x; }
|
||||
unsigned int true_value(unsigned int x) { return x; }
|
||||
unsigned long true_value(unsigned long x) { return x; }
|
||||
unsigned char true_value(unsigned char x) { return x; }
|
||||
|
||||
// The use of operators<> here tended to obscure interactions with certain
|
||||
// compiler bugs
|
||||
template <class T>
|
||||
class Wrapped1 : boost::operators<Wrapped1<T> >
|
||||
{
|
||||
public:
|
||||
explicit Wrapped1( T v = T() ) : _value(v) {}
|
||||
T value() const { return _value; }
|
||||
|
||||
bool operator<(const Wrapped1& x) const { return _value < x._value; }
|
||||
bool operator==(const Wrapped1& x) const { return _value == x._value; }
|
||||
|
||||
Wrapped1& operator+=(const Wrapped1& x)
|
||||
{ _value += x._value; return *this; }
|
||||
Wrapped1& operator-=(const Wrapped1& x)
|
||||
{ _value -= x._value; return *this; }
|
||||
Wrapped1& operator*=(const Wrapped1& x)
|
||||
{ _value *= x._value; return *this; }
|
||||
Wrapped1& operator/=(const Wrapped1& x)
|
||||
{ _value /= x._value; return *this; }
|
||||
Wrapped1& operator%=(const Wrapped1& x)
|
||||
{ _value %= x._value; return *this; }
|
||||
Wrapped1& operator|=(const Wrapped1& x)
|
||||
{ _value |= x._value; return *this; }
|
||||
Wrapped1& operator&=(const Wrapped1& x)
|
||||
{ _value &= x._value; return *this; }
|
||||
Wrapped1& operator^=(const Wrapped1& x)
|
||||
{ _value ^= x._value; return *this; }
|
||||
Wrapped1& operator++() { ++_value; return *this; }
|
||||
Wrapped1& operator--() { --_value; return *this; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
template <class T>
|
||||
T true_value(Wrapped1<T> x) { return x.value(); }
|
||||
|
||||
template <class T, class U>
|
||||
class Wrapped2 :
|
||||
boost::operators<Wrapped2<T, U> >,
|
||||
boost::operators2<Wrapped2<T, U>, U>
|
||||
{
|
||||
public:
|
||||
explicit Wrapped2( T v = T() ) : _value(v) {}
|
||||
T value() const { return _value; }
|
||||
|
||||
bool operator<(const Wrapped2& x) const { return _value < x._value; }
|
||||
bool operator==(const Wrapped2& x) const { return _value == x._value; }
|
||||
|
||||
Wrapped2& operator+=(const Wrapped2& x)
|
||||
{ _value += x._value; return *this; }
|
||||
Wrapped2& operator-=(const Wrapped2& x)
|
||||
{ _value -= x._value; return *this; }
|
||||
Wrapped2& operator*=(const Wrapped2& x)
|
||||
{ _value *= x._value; return *this; }
|
||||
Wrapped2& operator/=(const Wrapped2& x)
|
||||
{ _value /= x._value; return *this; }
|
||||
Wrapped2& operator%=(const Wrapped2& x)
|
||||
{ _value %= x._value; return *this; }
|
||||
Wrapped2& operator|=(const Wrapped2& x)
|
||||
{ _value |= x._value; return *this; }
|
||||
Wrapped2& operator&=(const Wrapped2& x)
|
||||
{ _value &= x._value; return *this; }
|
||||
Wrapped2& operator^=(const Wrapped2& x)
|
||||
{ _value ^= x._value; return *this; }
|
||||
Wrapped2& operator++() { ++_value; return *this; }
|
||||
Wrapped2& operator--() { --_value; return *this; }
|
||||
|
||||
bool operator<(U u) const { return _value < u; }
|
||||
bool operator>(U u) const { return _value > u; }
|
||||
bool operator==(U u) const { return _value == u; }
|
||||
Wrapped2& operator+=(U u) { _value += u; return *this; }
|
||||
Wrapped2& operator-=(U u) { _value -= u; return *this; }
|
||||
Wrapped2& operator*=(U u) { _value *= u; return *this; }
|
||||
Wrapped2& operator/=(U u) { _value /= u; return *this; }
|
||||
Wrapped2& operator%=(U u) { _value %= u; return *this; }
|
||||
Wrapped2& operator|=(U u) { _value |= u; return *this; }
|
||||
Wrapped2& operator&=(U u) { _value &= u; return *this; }
|
||||
Wrapped2& operator^=(U u) { _value ^= u; return *this; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
template <class T, class U>
|
||||
T true_value(Wrapped2<T,U> x) { return x.value(); }
|
||||
|
||||
// MyInt uses only the single template-argument form of all_operators<>
|
||||
typedef Wrapped1<int> MyInt;
|
||||
|
||||
typedef Wrapped2<long, long> MyLong;
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert(true_value(y1) == true_value(y2));
|
||||
assert(true_value(x1) == true_value(x2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_less_than_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 < y1) == (x2 < y2));
|
||||
assert((x1 <= y1) == (x2 <= y2));
|
||||
assert((x1 >= y1) == (x2 >= y2));
|
||||
assert((x1 > y1) == (x2 > y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_less_than_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_less_than_comparable_aux(x1, y1, x2, y2);
|
||||
test_less_than_comparable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_equality_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 == y1) == (x2 == y2));
|
||||
assert((x1 != y1) == (x2 != y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_equality_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_equality_comparable_aux(x1, y1, x2, y2);
|
||||
test_equality_comparable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_multipliable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 * y1).value() == (x2 * y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_multipliable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_multipliable_aux(x1, y1, x2, y2);
|
||||
test_multipliable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_addable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 + y1).value() == (x2 + y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_addable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_addable_aux(x1, y1, x2, y2);
|
||||
test_addable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_subtractable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
assert((x1 - y1).value() == x2 - y2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
if (y2 != 0)
|
||||
assert((x1 / y1).value() == x2 / y2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
if (y2 != 0)
|
||||
assert((x1 / y1).value() == x2 / y2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_xorable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 ^ y1).value() == (x2 ^ y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_xorable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_xorable_aux(x1, y1, x2, y2);
|
||||
test_xorable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_andable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 & y1).value() == (x2 & y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_andable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_andable_aux(x1, y1, x2, y2);
|
||||
test_andable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_orable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
assert((x1 | y1).value() == (x2 | y2));
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_orable(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
sanity_check(x1, y1, x2, y2);
|
||||
test_orable_aux(x1, y1, x2, y2);
|
||||
test_orable_aux(y1, x1, y2, x2);
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void test_incrementable(X1 x1, X2 x2)
|
||||
{
|
||||
sanity_check(x1, x1, x2, x2);
|
||||
assert(x1++.value() == x2++);
|
||||
assert(x1.value() == x2);
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void test_decrementable(X1 x1, X2 x2)
|
||||
{
|
||||
sanity_check(x1, x1, x2, x2);
|
||||
assert(x1--.value() == x2--);
|
||||
assert(x1.value() == x2);
|
||||
}
|
||||
|
||||
template <class X1, class Y1, class X2, class Y2>
|
||||
void test_all(X1 x1, Y1 y1, X2 x2, Y2 y2)
|
||||
{
|
||||
test_less_than_comparable(x1, y1, x2, y2);
|
||||
test_equality_comparable(x1, y1, x2, y2);
|
||||
test_multipliable(x1, y1, x2, y2);
|
||||
test_addable(x1, y1, x2, y2);
|
||||
test_subtractable(x1, y1, x2, y2);
|
||||
test_dividable(x1, y1, x2, y2);
|
||||
test_modable(x1, y1, x2, y2);
|
||||
test_xorable(x1, y1, x2, y2);
|
||||
test_andable(x1, y1, x2, y2);
|
||||
test_orable(x1, y1, x2, y2);
|
||||
test_incrementable(x1, x2);
|
||||
test_decrementable(x1, x2);
|
||||
}
|
||||
|
||||
template <class Big, class Small>
|
||||
struct tester
|
||||
{
|
||||
void operator()(boost::min_rand& randomizer) const
|
||||
{
|
||||
Big b1 = Big(randomizer());
|
||||
Big b2 = Big(randomizer());
|
||||
Small s = Small(randomizer());
|
||||
|
||||
test_all(Wrapped1<Big>(b1), Wrapped1<Big>(b2), b1, b2);
|
||||
test_all(Wrapped2<Big, Small>(b1), s, b1, s);
|
||||
}
|
||||
};
|
||||
|
||||
// added as a regression test. We had a bug which this uncovered.
|
||||
struct Point
|
||||
: boost::addable<Point,
|
||||
boost::subtractable<Point> >
|
||||
{
|
||||
Point( int h, int v ) : h(h), v(v) {}
|
||||
Point() :h(0), v(0) {}
|
||||
const Point& operator+=( const Point& rhs ) { h += rhs.h; v += rhs.v; return *this; }
|
||||
const Point& operator-=( const Point& rhs ) { h -= rhs.h; v -= rhs.v; return *this; }
|
||||
|
||||
int h;
|
||||
int v;
|
||||
};
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
// workaround for MSVC bug; for some reasons the compiler doesn't instantiate
|
||||
// inherited operator templates at the moment it must, so the following
|
||||
// explicit instantiations force it to do that.
|
||||
|
||||
#if defined(BOOST_MSVC) && (_MSC_VER <= 1200)
|
||||
template Wrapped1<int>;
|
||||
template Wrapped1<long>;
|
||||
template Wrapped1<unsigned int>;
|
||||
template Wrapped1<unsigned long>;
|
||||
|
||||
template Wrapped2<int, int>;
|
||||
template Wrapped2<int, signed char>;
|
||||
template Wrapped2<long, signed char>;
|
||||
template Wrapped2<long, int>;
|
||||
template Wrapped2<long, long>;
|
||||
template Wrapped2<unsigned int, unsigned int>;
|
||||
template Wrapped2<unsigned int, unsigned char>;
|
||||
template Wrapped2<unsigned long, unsigned int>;
|
||||
template Wrapped2<unsigned long, unsigned char>;
|
||||
template Wrapped2<unsigned long, unsigned long>;
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#error This program is pointless when NDEBUG disables assert()!
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
// Regression test.
|
||||
Point x;
|
||||
x = x + Point(3, 4);
|
||||
x = x - Point(3, 4);
|
||||
|
||||
for (int n = 0; n < 10000; ++n)
|
||||
{
|
||||
boost::min_rand r;
|
||||
tester<long, int>()(r);
|
||||
tester<long, signed char>()(r);
|
||||
tester<long, long>()(r);
|
||||
tester<int, int>()(r);
|
||||
tester<int, signed char>()(r);
|
||||
|
||||
tester<unsigned long, unsigned int>()(r);
|
||||
tester<unsigned long, unsigned char>()(r);
|
||||
tester<unsigned long, unsigned long>()(r);
|
||||
tester<unsigned int, unsigned int>()(r);
|
||||
tester<unsigned int, unsigned char>()(r);
|
||||
}
|
||||
|
||||
MyInt i1(1);
|
||||
MyInt i2(2);
|
||||
MyInt i;
|
||||
|
||||
assert( i1.value() == 1 );
|
||||
assert( i2.value() == 2 );
|
||||
assert( i.value() == 0 );
|
||||
|
||||
i = i2;
|
||||
assert( i.value() == 2 );
|
||||
assert( i2 == i );
|
||||
assert( i1 != i2 );
|
||||
assert( i1 < i2 );
|
||||
assert( i1 <= i2 );
|
||||
assert( i <= i2 );
|
||||
assert( i2 > i1 );
|
||||
assert( i2 >= i1 );
|
||||
assert( i2 >= i );
|
||||
|
||||
i = i1 + i2; assert( i.value() == 3 );
|
||||
i = i + i2; assert( i.value() == 5 );
|
||||
i = i - i1; assert( i.value() == 4 );
|
||||
i = i * i2; assert( i.value() == 8 );
|
||||
i = i / i2; assert( i.value() == 4 );
|
||||
i = i % (i - i1); assert( i.value() == 1 );
|
||||
i = i2 + i2; assert( i.value() == 4 );
|
||||
i = i1 | i2 | i; assert( i.value() == 7 );
|
||||
i = i & i2; assert( i.value() == 2 );
|
||||
i = i + i1; assert( i.value() == 3 );
|
||||
i = i ^ i1; assert( i.value() == 2 );
|
||||
i = (i+i1)*(i2|i1); assert( i.value() == 9 );
|
||||
|
||||
MyLong j1(1);
|
||||
MyLong j2(2);
|
||||
MyLong j;
|
||||
|
||||
assert( j1.value() == 1 );
|
||||
assert( j2.value() == 2 );
|
||||
assert( j.value() == 0 );
|
||||
|
||||
j = j2;
|
||||
assert( j.value() == 2 );
|
||||
|
||||
assert( j2 == j );
|
||||
assert( 2 == j );
|
||||
assert( j2 == 2 );
|
||||
assert( j == j2 );
|
||||
assert( j1 != j2 );
|
||||
assert( j1 != 2 );
|
||||
assert( 1 != j2 );
|
||||
assert( j1 < j2 );
|
||||
assert( 1 < j2 );
|
||||
assert( j1 < 2 );
|
||||
assert( j1 <= j2 );
|
||||
assert( 1 <= j2 );
|
||||
assert( j1 <= j );
|
||||
assert( j <= j2 );
|
||||
assert( 2 <= j2 );
|
||||
assert( j <= 2 );
|
||||
assert( j2 > j1 );
|
||||
assert( 2 > j1 );
|
||||
assert( j2 > 1 );
|
||||
assert( j2 >= j1 );
|
||||
assert( 2 >= j1 );
|
||||
assert( j2 >= 1 );
|
||||
assert( j2 >= j );
|
||||
assert( 2 >= j );
|
||||
assert( j2 >= 2 );
|
||||
|
||||
assert( (j1 + 2) == 3 );
|
||||
assert( (1 + j2) == 3 );
|
||||
j = j1 + j2; assert( j.value() == 3 );
|
||||
|
||||
assert( (j + 2) == 5 );
|
||||
assert( (3 + j2) == 5 );
|
||||
j = j + j2; assert( j.value() == 5 );
|
||||
|
||||
assert( (j - 1) == 4 );
|
||||
j = j - j1; assert( j.value() == 4 );
|
||||
|
||||
assert( (j * 2) == 8 );
|
||||
assert( (4 * j2) == 8 );
|
||||
j = j * j2; assert( j.value() == 8 );
|
||||
|
||||
assert( (j / 2) == 4 );
|
||||
j = j / j2; assert( j.value() == 4 );
|
||||
|
||||
assert( (j % 3) == 1 );
|
||||
j = j % (j - j1); assert( j.value() == 1 );
|
||||
|
||||
j = j2 + j2; assert( j.value() == 4 );
|
||||
|
||||
assert( (1 | j2 | j) == 7 );
|
||||
assert( (j1 | 2 | j) == 7 );
|
||||
assert( (j1 | j2 | 4) == 7 );
|
||||
j = j1 | j2 | j; assert( j.value() == 7 );
|
||||
|
||||
assert( (7 & j2) == 2 );
|
||||
assert( (j & 2) == 2 );
|
||||
j = j & j2; assert( j.value() == 2 );
|
||||
|
||||
j = j | j1; assert( j.value() == 3 );
|
||||
|
||||
assert( (3 ^ j1) == 2 );
|
||||
assert( (j ^ 1) == 2 );
|
||||
j = j ^ j1; assert( j.value() == 2 );
|
||||
|
||||
j = (j+j1)*(j2|j1); assert( j.value() == 9 );
|
||||
|
||||
std::cout << "0 errors detected\n";
|
||||
return 0;
|
||||
}
|
137
tie.html
137
tie.html
@ -1,137 +0,0 @@
|
||||
<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/docs/bibliography.html#jaakko_tuple_assign">1</A>].
|
||||
|
||||
<P>
|
||||
|
||||
<H3>Where Defined</H3>
|
||||
|
||||
<P>
|
||||
<a href="../../boost/utility.hpp"><TT>boost/utility.hpp</TT></a>
|
||||
|
||||
<P>
|
||||
|
||||
<H3>Example</H3>
|
||||
|
||||
<P>
|
||||
An example of using the <TT>tie()</TT> function with the
|
||||
<TT>vertices()</TT> function, which returns a pair of
|
||||
type <TT>std::pair<vertex_iterator,vertex_iterator></TT>. The
|
||||
pair of iterators is assigned to the iterator variables <TT>i</TT> and
|
||||
<TT>end</TT>.
|
||||
|
||||
<P>
|
||||
<PRE>
|
||||
graph_traits< adjacency_list<> >::vertex_iterator i, end;
|
||||
for(tie(i,end) = vertices(G); i != end; ++i)
|
||||
// ...
|
||||
</PRE>
|
||||
|
||||
<P>
|
||||
Here is another example that uses <TT>tie()</TT> for handling operations with <a
|
||||
href="http://www.sgi.com/Technology/STL/set.html"><TT>std::set</TT></a>.
|
||||
|
||||
<P>
|
||||
<PRE>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
{
|
||||
typedef std::set<int> SetT;
|
||||
SetT::iterator i, end;
|
||||
bool inserted;
|
||||
|
||||
int vals[5] = { 5, 2, 4, 9, 1 };
|
||||
SetT s(vals, vals + 5);
|
||||
|
||||
// Using tie() with a return value of pair<iterator,bool>
|
||||
|
||||
int new_vals[2] = { 3, 9 };
|
||||
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
boost::tie(i,inserted) = s.insert(new_vals[k]);
|
||||
if (!inserted)
|
||||
std::cout << *i << " was already in the set." << std::endl;
|
||||
else
|
||||
std::cout << *i << " successfully inserted." << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
int* i, *end;
|
||||
int vals[6] = { 5, 2, 4, 4, 9, 1 };
|
||||
std::sort(vals, vals + 6);
|
||||
|
||||
// Using tie() with a return value of pair<iterator,iterator>
|
||||
|
||||
boost::tie(i,end) = std::equal_range(vals, vals + 6, 4);
|
||||
std::cout << "There were " << std::distance(i,end)
|
||||
<< " occurrences of " << *i << "." << std::endl;
|
||||
// Footnote: of course one would normally just use std::count()
|
||||
// to get this information, but that would spoil the example :)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</PRE>
|
||||
The output is:
|
||||
<PRE>
|
||||
3 successfully inserted.
|
||||
9 was already in the set.
|
||||
There were 2 occurrences of 4.
|
||||
</PRE>
|
||||
|
||||
<br>
|
||||
<HR>
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>,
|
||||
Univ.of Notre Dame (<A
|
||||
HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)<br>
|
||||
<A HREF=http://www.lsc.nd.edu/~llee1>Lie-Quan Lee</A>, Univ.of Notre Dame (<A HREF="mailto:llee1@lsc.nd.edu">llee1@lsc.nd.edu</A>)<br>
|
||||
<A HREF=http://www.lsc.nd.edu/~lums>Andrew Lumsdaine</A>,
|
||||
Univ.of Notre Dame (<A
|
||||
HREF="mailto:lums@lsc.nd.edu">lums@lsc.nd.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
@ -1,61 +0,0 @@
|
||||
// (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;
|
||||
}
|
626
type_traits.htm
626
type_traits.htm
@ -1,626 +0,0 @@
|
||||
<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>Type Traits</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
||||
|
||||
<h1><img src="../../c++boost.gif" width="276" height="86">Header
|
||||
<<a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a>></h1>
|
||||
|
||||
<p>The contents of <boost/type_traits.hpp> are declared in
|
||||
namespace boost.</p>
|
||||
|
||||
<p>The file <<a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a>>
|
||||
contains various template classes that describe the fundamental
|
||||
properties of a type; each class represents a single type
|
||||
property or a single type transformation. This documentation is
|
||||
divided up into the following sections:</p>
|
||||
|
||||
<pre><a href="#fop">Fundamental type operations</a>
|
||||
<a href="#fp">Fundamental type properties</a>
|
||||
<a href="#misc">Miscellaneous</a>
|
||||
<code> </code><a href="#cv">cv-Qualifiers</a>
|
||||
<code> </code><a href="#ft">Fundamental Types</a>
|
||||
<code> </code><a href="#ct">Compound Types</a>
|
||||
<code> </code><a href="#ot">Object/Scalar Types</a>
|
||||
<a href="#cs">Compiler Support Information</a>
|
||||
<a href="#ec">Example Code</a></pre>
|
||||
|
||||
<h2><a name="fop"></a>Fundamental type operations</h2>
|
||||
|
||||
<p>Usage: "class_name<T>::type" performs
|
||||
indicated transformation on type T.</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td valign="top" width="45%"><p align="center">Expression.</p>
|
||||
</td>
|
||||
<td valign="top" width="45%"><p align="center">Description.</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">Compiler.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>remove_volatile<T>::type</code></td>
|
||||
<td valign="top" width="45%">Creates a type the same as T
|
||||
but with any top level volatile qualifier removed. For
|
||||
example "volatile int" would become "int".</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>remove_const<T>::type</code></td>
|
||||
<td valign="top" width="45%">Creates a type the same as T
|
||||
but with any top level const qualifier removed. For
|
||||
example "const int" would become "int".</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>remove_cv<T>::type</code></td>
|
||||
<td valign="top" width="45%">Creates a type the same as T
|
||||
but with any top level cv-qualifiers removed. For example
|
||||
"const int" would become "int", and
|
||||
"volatile double" would become "double".</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>remove_reference<T>::type</code></td>
|
||||
<td valign="top" width="45%">If T is a reference type
|
||||
then removes the reference, otherwise leaves T unchanged.
|
||||
For example "int&" becomes "int"
|
||||
but "int*" remains unchanged.</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>add_reference<T>::type</code></td>
|
||||
<td valign="top" width="45%">If T is a reference type
|
||||
then leaves T unchanged, otherwise converts T to a
|
||||
reference type. For example "int&" remains
|
||||
unchanged, but "double" becomes "double&".</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>remove_bounds<T>::type</code></td>
|
||||
<td valign="top" width="45%">If T is an array type then
|
||||
removes the top level array qualifier from T, otherwise
|
||||
leaves T unchanged. For example "int[2][3]"
|
||||
becomes "int[3]".</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h2><a name="fp"></a>Fundamental type properties</h2>
|
||||
|
||||
<p>Usage: "class_name<T>::value" is true if
|
||||
indicated property is true, false otherwise. (Note that class_name<T>::value
|
||||
is always defined as a compile time constant).</p>
|
||||
|
||||
<h3><a name="misc"></a>Miscellaneous</h3>
|
||||
|
||||
<table border="1" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td width="37%"><p align="center">Expression</p>
|
||||
</td>
|
||||
<td width="36%"><p align="center">Description</p>
|
||||
</td>
|
||||
<td width="27%"><p align="center">Compiler</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="37%"><div align="center"><center><pre><code>is_same<T,U>::value</code></pre>
|
||||
</center></div></td>
|
||||
<td width="36%"><p align="center">True if T and U are the
|
||||
same type.</p>
|
||||
</td>
|
||||
<td width="27%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="37%"><div align="center"><center><pre>is_convertible<T,U>::value</pre>
|
||||
</center></div></td>
|
||||
<td width="36%"><p align="center">True if type T is
|
||||
convertible to type U.</p>
|
||||
</td>
|
||||
<td width="27%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="37%"><div align="center"><center><pre>alignment_of<T>::value</pre>
|
||||
</center></div></td>
|
||||
<td width="36%"><p align="center">An integral value
|
||||
representing the minimum alignment requirements of type T
|
||||
(strictly speaking defines a multiple of the type's
|
||||
alignment requirement; for all compilers tested so far
|
||||
however it does return the actual alignment).</p>
|
||||
</td>
|
||||
<td width="27%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3><a name="cv"></a>cv-Qualifiers</h3>
|
||||
|
||||
<p>The following classes determine what cv-qualifiers are present
|
||||
on a type (see 3.93).</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td valign="top" width="37%"><p align="center">Expression.</p>
|
||||
</td>
|
||||
<td valign="top" width="37%"><p align="center">Description.</p>
|
||||
</td>
|
||||
<td valign="top" width="27%"><p align="center">Compiler.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="37%"><code>is_const<T>::value</code></td>
|
||||
<td valign="top" width="37%">True if type T is top-level
|
||||
const qualified.</td>
|
||||
<td valign="top" width="27%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="37%"><code>is_volatile<T>::value</code></td>
|
||||
<td valign="top" width="37%">True if type T is top-level
|
||||
volatile qualified.</td>
|
||||
<td valign="top" width="27%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3><a name="ft"></a>Fundamental Types</h3>
|
||||
|
||||
<p>The following will only ever be true for cv-unqualified types;
|
||||
these are closely based on the section 3.9 of the C++ Standard.</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td valign="top" width="45%"><p align="center">Expression.</p>
|
||||
</td>
|
||||
<td valign="top" width="45%"><p align="center">Description.</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">Compiler.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_void<T>::value</code></td>
|
||||
<td valign="top" width="45%">True only if T is void.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_unsigned_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True only if T is one of the
|
||||
standard unsigned integral types (3.9.1 p3) - unsigned
|
||||
char, unsigned short, unsigned int, and unsigned long.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_signed_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True only if T is one of the
|
||||
standard signed integral types (3.9.1 p2) - signed char,
|
||||
short, int, and long.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a standard
|
||||
integral type(3.9.1 p7) - T is either char, wchar_t, bool
|
||||
or either is_standard_signed_integral<T>::value or
|
||||
is_standard_integral<T>::value is true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_float<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is one of the
|
||||
standard floating point types(3.9.1 p8) - float, double
|
||||
or long double.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_arithmetic<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a standard
|
||||
arithmetic type(3.9.1 p8) - implies is_standard_integral
|
||||
or is_standard_float is true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_fundamental<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a standard
|
||||
arithmetic type or if T is void.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_unsigned_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True for compiler specific
|
||||
unsigned integral types.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_signed_integral<T>>:value</code></td>
|
||||
<td valign="top" width="45%">True for compiler specific
|
||||
signed integral types.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_extension_unsigned_integral<T>::value
|
||||
or is_extension_signed_integral<T>::value is true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_float<T>::value</code></td>
|
||||
<td valign="top" width="45%">True for compiler specific
|
||||
floating point types.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_arithmetic<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_extension_integral<T>::value
|
||||
or is_extension_float<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code> is_extension_fundamental<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_extension_arithmetic<T>::value
|
||||
or is_void<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code> is_unsigned_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_standard_unsigned_integral<T>::value
|
||||
or is_extention_unsigned_integral<T>::value are
|
||||
true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_signed_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_standard_signed_integral<T>::value
|
||||
or is_extention_signed_integral<T>>::value are
|
||||
true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_integral<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_standard_integral<T>::value
|
||||
or is_extention_integral<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_float<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_standard_float<T>::value
|
||||
or is_extention_float<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_arithmetic<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_integral<T>::value
|
||||
or is_float<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_fundamental<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if either is_arithmetic<T>::value
|
||||
or is_void<T>::value are true.</td>
|
||||
<td valign="top" width="33%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3><a name="ct"></a>Compound Types</h3>
|
||||
|
||||
<p>The following will only ever be true for cv-unqualified types,
|
||||
as defined by the Standard. </p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td valign="top" width="45%"><p align="center">Expression</p>
|
||||
</td>
|
||||
<td valign="top" width="45%"><p align="center">Description</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">Compiler</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_array<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is an array type.</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_pointer<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a regular
|
||||
pointer type - including function pointers - but
|
||||
excluding pointers to member functions (3.9.2 p1 and 8.3.1).</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_member_pointer<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a pointer to a
|
||||
non-static class member (3.9.2 p1 and 8.3.1).</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_reference<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a reference
|
||||
type (3.9.2 p1 and 8.3.2).</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_class<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a class or
|
||||
struct type.</td>
|
||||
<td valign="top" width="33%"><p align="center">PD</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_union<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a union type.</td>
|
||||
<td valign="top" width="33%"><p align="center">C</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_enum<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is an enumerator
|
||||
type.</td>
|
||||
<td valign="top" width="33%"><p align="center">C</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_compound<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is any of the
|
||||
above compound types.</td>
|
||||
<td valign="top" width="33%"><p align="center">PD</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h3><a name="ot"></a>Object/Scalar Types</h3>
|
||||
|
||||
<p>The following ignore any top level cv-qualifiers: if <code>class_name<T>::value</code>
|
||||
is true then <code>class_name<cv-qualified-T>::value</code>
|
||||
will also be true.</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="100%">
|
||||
<tr>
|
||||
<td valign="top" width="45%"><p align="center">Expression</p>
|
||||
</td>
|
||||
<td valign="top" width="45%"><p align="center">Description</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">Compiler</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_object<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is not a reference
|
||||
type, or a (possibly cv-qualified) void type.</td>
|
||||
<td valign="top" width="33%"><p align="center">P</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_standard_scalar<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a standard
|
||||
arithmetic type, an enumerated type, a pointer or a
|
||||
member pointer.</td>
|
||||
<td valign="top" width="33%"><p align="center">PD</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_extension_scalar<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is an extentions
|
||||
arithmetic type, an enumerated type, a pointer or a
|
||||
member pointer.</td>
|
||||
<td valign="top" width="33%"><p align="center">PD</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_scalar<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is an arithmetic
|
||||
type, an enumerated type, a pointer or a member pointer.</td>
|
||||
<td valign="top" width="33%"><p align="center">PD</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_POD<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is a "Plain
|
||||
Old Data" type (see 3.9 p2&p3). Note that
|
||||
although this requires compiler support to be correct in
|
||||
all cases, if T is a scalar or an array of scalars then
|
||||
we can correctly define T as a POD.</td>
|
||||
<td valign="top" width="33%"><p align="center">PC</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>is_empty<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T is an empty struct
|
||||
or class. If the compiler implements the "zero sized
|
||||
empty base classes" optimisation, then is_empty will
|
||||
correctly guess whether T is empty. Relies upon is_class
|
||||
to determine whether T is a class type. Screens out enum
|
||||
types by using is_convertible<T,int>, this means
|
||||
that empty classes that overload operator int(), will not
|
||||
be classified as empty.</td>
|
||||
<td valign="top" width="33%"><p align="center">PCD</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>has_trivial_constructor<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T has a trivial
|
||||
default constructor - that is T() is equivalent to memset.</td>
|
||||
<td valign="top" width="33%"><p align="center">PC</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>has_trivial_copy<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T has a trivial copy
|
||||
constructor - that is T(const T&) is equivalent to
|
||||
memcpy.</td>
|
||||
<td valign="top" width="33%"><p align="center">PC</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>has_trivial_assign<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T has a trivial
|
||||
assignment operator - that is if T::operator=(const T&)
|
||||
is equivalent to memcpy.</td>
|
||||
<td valign="top" width="33%"><p align="center">PC</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="45%"><code>has_trivial_destructor<T>::value</code></td>
|
||||
<td valign="top" width="45%">True if T has a trivial
|
||||
destructor - that is if T::~T() has no effect.</td>
|
||||
<td valign="top" width="33%"><p align="center">PC</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h2><a name="cs"></a>Compiler Support Information</h2>
|
||||
|
||||
<p>The legends used in the tables above have the following
|
||||
meanings:</p>
|
||||
|
||||
<table border="0" cellpadding="7" cellspacing="0" width="480">
|
||||
<tr>
|
||||
<td valign="top" width="50%"><p align="center">P</p>
|
||||
</td>
|
||||
<td valign="top" width="90%">Denotes that the class
|
||||
requires support for partial specialisation of class
|
||||
templates to work correctly.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><p align="center">C</p>
|
||||
</td>
|
||||
<td valign="top" width="90%">Denotes that direct compiler
|
||||
support for that traits class is required.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><p align="center">D</p>
|
||||
</td>
|
||||
<td valign="top" width="90%">Denotes that the traits
|
||||
class is dependent upon a class that requires direct
|
||||
compiler support.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p>For those classes that are marked with a D or C, if compiler
|
||||
support is not provided, this type trait may return "false"
|
||||
when the correct value is actually "true". The single
|
||||
exception to this rule is "is_class", which attempts to
|
||||
guess whether or not T is really a class, and may return "true"
|
||||
when the correct value is actually "false". This can
|
||||
happen if: T is a union, T is an enum, or T is a compiler-supplied
|
||||
scalar type that is not specialised for in these type traits.</p>
|
||||
|
||||
<p><i>If there is no compiler support</i>, to ensure that these
|
||||
traits <i>always</i> return the correct values, specialise 'is_enum'
|
||||
for each user-defined enumeration type, 'is_union' for each user-defined
|
||||
union type, 'is_empty' for each user-defined empty composite type,
|
||||
and 'is_POD' for each user-defined POD type. The 'has_*' traits
|
||||
should also be specialized if the user-defined type has those
|
||||
traits and is <i>not</i> a POD.</p>
|
||||
|
||||
<p>The following rules are automatically enforced:</p>
|
||||
|
||||
<p>is_enum implies is_POD</p>
|
||||
|
||||
<p>is_POD implies has_*</p>
|
||||
|
||||
<p>This means, for example, if you have an empty POD-struct, just
|
||||
specialize is_empty and is_POD, which will cause all the has_* to
|
||||
also return true.</p>
|
||||
|
||||
<h2><a name="ec"></a>Example code</h2>
|
||||
|
||||
<p>Type-traits comes with two sample programs: <a
|
||||
href="type_traits_test.cpp">type_traits_test.cpp</a> tests the
|
||||
type traits classes - mostly this is a test of your compiler's
|
||||
support for the concepts used in the type traits implementation,
|
||||
while <a href="algo_opt_examples.cpp">algo_opt_examples.cpp</a>
|
||||
uses the type traits classes to "optimise" some
|
||||
familiar standard library algorithms.</p>
|
||||
|
||||
<p>There are four algorithm examples in algo_opt_examples.cpp:</p>
|
||||
|
||||
<table border="0" cellpadding="7" cellspacing="0" width="638">
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>opt::copy</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">If the copy operation can be
|
||||
performed using memcpy then does so, otherwise uses a
|
||||
regular element by element copy (<i>c.f.</i> std::copy).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>opt::fill</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">If the fill operation can be
|
||||
performed by memset, then does so, otherwise uses a
|
||||
regular element by element assign. Also uses call_traits
|
||||
to optimise how the parameters can be passed (<i>c.f.</i>
|
||||
std::fill).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>opt::destroy_array</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">If the type in the array has
|
||||
a trivial destructor then does nothing, otherwise calls
|
||||
destructors for all elements in the array - this
|
||||
algorithm is the reverse of std::uninitialized_copy / std::uninitialized_fill.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>opt::iter_swap</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%">Determines whether the
|
||||
iterator is a proxy-iterator: if it is then does a "slow
|
||||
and safe" swap, otherwise calls std::swap on the
|
||||
assumption that std::swap may be specialised for the
|
||||
iterated type.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised 08<sup>th</sup> March 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.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p>
|
||||
</body>
|
||||
</html>
|
@ -1,595 +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.
|
||||
|
||||
// standalone test program for <boost/type_traits.hpp>
|
||||
|
||||
/* Release notes:
|
||||
31st July 2000:
|
||||
Added extra tests for is_empty, is_convertible, alignment_of.
|
||||
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>
|
||||
#include "type_traits_test.hpp"
|
||||
|
||||
using namespace boost;
|
||||
|
||||
// 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
|
||||
|
||||
class Base { };
|
||||
|
||||
class Deriverd : public Base { };
|
||||
|
||||
class NonDerived { };
|
||||
|
||||
enum enum1
|
||||
{
|
||||
one_,two_
|
||||
};
|
||||
|
||||
enum enum2
|
||||
{
|
||||
three_,four_
|
||||
};
|
||||
|
||||
struct VB
|
||||
{
|
||||
virtual ~VB(){};
|
||||
};
|
||||
|
||||
struct VD : VB
|
||||
{
|
||||
~VD(){};
|
||||
};
|
||||
|
||||
|
||||
// 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)
|
||||
#ifdef __MWERKS__
|
||||
// apparent compiler bug causes this to fail to compile:
|
||||
value_fail(false, is_empty<int[2]>::value)
|
||||
#else
|
||||
value_test(false, is_empty<int[2]>::value)
|
||||
#endif
|
||||
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)
|
||||
|
||||
value_test(true, (boost::is_convertible<Deriverd,Base>::value));
|
||||
value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value));
|
||||
value_test(true, (boost::is_convertible<Base,Base>::value));
|
||||
value_test(false, (boost::is_convertible<Base,Deriverd>::value));
|
||||
value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value));
|
||||
value_test(false, (boost::is_convertible<NonDerived,Base>::value));
|
||||
//value_test(false, (boost::is_convertible<boost::noncopyable, boost::noncopyable>::value));
|
||||
value_test(true, (boost::is_convertible<float,int>::value));
|
||||
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
value_test(false, (boost::is_convertible<float,void>::value));
|
||||
value_test(false, (boost::is_convertible<void,float>::value));
|
||||
value_test(true, (boost::is_convertible<void,void>::value));
|
||||
#endif
|
||||
value_test(true, (boost::is_convertible<enum1, int>::value));
|
||||
value_test(true, (boost::is_convertible<Deriverd*, Base*>::value));
|
||||
value_test(false, (boost::is_convertible<Base*, Deriverd*>::value));
|
||||
value_test(true, (boost::is_convertible<Deriverd&, Base&>::value));
|
||||
value_test(false, (boost::is_convertible<Base&, Deriverd&>::value));
|
||||
value_test(true, (boost::is_convertible<const Deriverd*, const Base*>::value));
|
||||
value_test(false, (boost::is_convertible<const Base*, const Deriverd*>::value));
|
||||
value_test(true, (boost::is_convertible<const Deriverd&, const Base&>::value));
|
||||
value_test(false, (boost::is_convertible<const Base&, const Deriverd&>::value));
|
||||
|
||||
value_test(false, (boost::is_convertible<const int *, int*>::value));
|
||||
value_test(false, (boost::is_convertible<const int&, int&>::value));
|
||||
value_test(false, (boost::is_convertible<int*, int[2]>::value));
|
||||
value_test(false, (boost::is_convertible<const int*, int[3]>::value));
|
||||
value_test(true, (boost::is_convertible<const int&, int>::value));
|
||||
value_test(true, (boost::is_convertible<int(&)[4], const int*>::value));
|
||||
value_test(true, (boost::is_convertible<int(&)(int), int(*)(int)>::value));
|
||||
value_test(true, (boost::is_convertible<int *, const int*>::value));
|
||||
value_test(true, (boost::is_convertible<int&, const int&>::value));
|
||||
value_test(true, (boost::is_convertible<int[2], int*>::value));
|
||||
value_test(true, (boost::is_convertible<int[2], const int*>::value));
|
||||
value_test(false, (boost::is_convertible<const int[2], int*>::value));
|
||||
|
||||
align_test(int);
|
||||
align_test(char);
|
||||
align_test(double);
|
||||
align_test(int[4]);
|
||||
align_test(int(*)(int));
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
align_test(char&);
|
||||
align_test(char (&)(int));
|
||||
align_test(char(&)[4]);
|
||||
#endif
|
||||
align_test(int*);
|
||||
//align_test(const int);
|
||||
align_test(VB);
|
||||
align_test(VD);
|
||||
|
||||
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||
std::cin.get();
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,106 +0,0 @@
|
||||
// boost::compressed_pair test program
|
||||
|
||||
// (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
// common test code for type_traits_test.cpp/call_traits_test.cpp/compressed_pair_test.cpp
|
||||
|
||||
|
||||
#ifndef BOOST_TYPE_TRAITS_TEST_HPP
|
||||
#define BOOST_TYPE_TRAITS_TEST_HPP
|
||||
|
||||
//
|
||||
// this one is here just to suppress warnings:
|
||||
//
|
||||
template <class T>
|
||||
bool do_compare(T i, T j)
|
||||
{
|
||||
return i == j;
|
||||
}
|
||||
|
||||
//
|
||||
// this one is to verify that a constant is indeed a
|
||||
// constant-integral-expression:
|
||||
//
|
||||
template <int>
|
||||
struct ct_checker
|
||||
{
|
||||
};
|
||||
|
||||
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
|
||||
#define BOOST_DO_JOIN2(X, Y) X ## Y
|
||||
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
|
||||
|
||||
|
||||
#define value_test(v, x) ++test_count;\
|
||||
typedef ct_checker<(x)> BOOST_JOIN(this_is_a_compile_time_check_, __LINE__);\
|
||||
if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;}
|
||||
#define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
#define type_test(v, x) ++test_count;\
|
||||
if(do_compare(boost::is_same<v, x>::value, false)){\
|
||||
++failures; \
|
||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
||||
std::cout << " expected type was " << #v << std::endl; \
|
||||
std::cout << " " << typeid(boost::is_same<v, x>).name() << "::value is false" << std::endl; }
|
||||
#else
|
||||
#define type_test(v, x) ++test_count;\
|
||||
if(typeid(v) != typeid(x)){\
|
||||
++failures; \
|
||||
std::cout << "checking type of " << #x << "...failed" << std::endl; \
|
||||
std::cout << " expected type was " << #v << std::endl; \
|
||||
std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; }
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct test_align
|
||||
{
|
||||
struct padded
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
static void do_it()
|
||||
{
|
||||
padded p;
|
||||
unsigned a = reinterpret_cast<char*>(&(p.t)) - reinterpret_cast<char*>(&p);
|
||||
value_test(a, boost::alignment_of<T>::value);
|
||||
}
|
||||
};
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <class T>
|
||||
struct test_align<T&>
|
||||
{
|
||||
static void do_it()
|
||||
{
|
||||
//
|
||||
// we can't do the usual test because we can't take the address
|
||||
// of a reference, so check that the result is the same as for a
|
||||
// pointer type instead:
|
||||
value_test(boost::alignment_of<T*>::value, boost::alignment_of<T&>::value);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#define align_test(T) test_align<T>::do_it()
|
||||
|
||||
//
|
||||
// define tests here
|
||||
unsigned failures = 0;
|
||||
unsigned test_count = 0;
|
||||
|
||||
//
|
||||
// turn off some warnings:
|
||||
#ifdef __BORLANDC__
|
||||
#pragma option -w-8004
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning (disable: 4018)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // BOOST_TYPE_TRAITS_TEST_HPP
|
104
utility.htm
104
utility.htm
@ -1,104 +0,0 @@
|
||||
<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="#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> <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 : 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>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
|
||||
-->28 September, 2000<!--webbot bot="Timestamp" endspan i-checksum="39343"
|
||||
-->
|
||||
</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