Compare commits

..

189 Commits

Author SHA1 Message Date
Jeremy Siek
7cfd6f756d removed redundant "in in"
[SVN r11111]
2001-09-13 13:56:37 +00:00
Jeremy Siek
4e1b693ee2 updated STL links
[SVN r11040]
2001-09-05 22:45:51 +00:00
Dave Abrahams
e7592e5f83 Added a mention of the pair_generator; updated conclusion to stress Policy Adaptor.
[SVN r11039]
2001-09-05 18:33:04 +00:00
Jeremy Siek
d41013d9dc capitalized "standard"
[SVN r11038]
2001-09-05 17:49:36 +00:00
Jeremy Siek
c3c8871f87 removed accidental "Executing ssh-askpass" stuff
[SVN r11037]
2001-09-05 17:44:35 +00:00
Jeremy Siek
7b2f7a5ab4 removed "alternate solution" for object generators
[SVN r11036]
2001-09-05 17:43:20 +00:00
Jeremy Siek
bef6ec31f0 added citation for named params
[SVN r11034]
2001-09-05 15:56:14 +00:00
Jeremy Siek
7657f5f343 added named template param reference
[SVN r11033]
2001-09-05 15:55:58 +00:00
Jeremy Siek
1a31e19cfe some "generator" changes
[SVN r11032]
2001-09-05 15:32:01 +00:00
Dave Abrahams
82377d5130 polishing
[SVN r11029]
2001-09-05 12:36:27 +00:00
Dave Abrahams
4fe8f1505f added a missing word
[SVN r11028]
2001-09-05 05:58:21 +00:00
Dave Abrahams
c11ba92add Rewrote the object generator section, among other things.
[SVN r11027]
2001-09-05 03:46:11 +00:00
Jeremy Siek
c3cb4753f5 changed some wording with respect to the term concepts
[SVN r11019]
2001-09-04 15:30:12 +00:00
Jeremy Siek
80eb3699d7 slight change to title
removed footnote
removed default_iterator_policies::less


[SVN r11018]
2001-09-04 14:51:02 +00:00
Jeremy Siek
0e40c56a87 changed title
[SVN r10999]
2001-09-03 15:49:13 +00:00
Jeremy Siek
4a79874032 added refs for LEDA and SGB
[SVN r10995]
2001-09-03 05:02:35 +00:00
Jeremy Siek
4e07a06b94 changed the title
[SVN r10994]
2001-09-03 04:59:01 +00:00
Jeremy Siek
884c36772a some edits
[SVN r10993]
2001-09-03 04:57:57 +00:00
Dave Abrahams
506334c120 edits. What can I say?
[SVN r10992]
2001-09-02 04:42:43 +00:00
Jeremy Siek
89107738b3 some edits/reorganizations
[SVN r10991]
2001-09-02 02:29:12 +00:00
Dave Abrahams
397946a114 swapped two words, fixed typo
[SVN r10990]
2001-09-01 21:03:07 +00:00
Dave Abrahams
ddbc514208 total reorg. Whew!
[SVN r10989]
2001-09-01 20:59:13 +00:00
Dave Abrahams
2cef48d02a intermediate state checkin
[SVN r10988]
2001-09-01 20:02:52 +00:00
Dave Abrahams
96a079e30a Fixed the numerous TeX errors!
[SVN r10977]
2001-08-31 18:11:55 +00:00
Dave Abrahams
4a3f6877e2 Improved section on computing defaults
[SVN r10974]
2001-08-31 11:13:34 +00:00
Dave Abrahams
c593a27a51 Many edits based on review comments
[SVN r10939]
2001-08-27 03:13:15 +00:00
Dave Abrahams
f94db51996 updated abstract
[SVN r10337]
2001-06-15 12:47:22 +00:00
Dave Abrahams
3e5b447aa3 no message
[SVN r10336]
2001-06-15 02:23:19 +00:00
Jeremy Siek
2f9bd13902 some minor edits
[SVN r10331]
2001-06-14 16:38:28 +00:00
Jeremy Siek
c59a5e8783 added section describing named parameters, default parameters, and
a conclusion


[SVN r10328]
2001-06-14 16:02:58 +00:00
Jeremy Siek
5b716a8b19 small edit
[SVN r10316]
2001-06-12 19:32:35 +00:00
Jeremy Siek
c243d693e2 made some more progress, starting filling in stuff about the implementation
[SVN r10315]
2001-06-12 19:03:23 +00:00
Dave Abrahams
b950b3afed Some edits to Jeremy's original text
Filled out input iterator operator-> section


[SVN r10283]
2001-06-06 23:09:40 +00:00
Jeremy Siek
1c555eae91 small edit
[SVN r10282]
2001-06-06 20:41:32 +00:00
Jeremy Siek
f04178d055 worked on the section about the operator[] problem
[SVN r10281]
2001-06-06 20:39:34 +00:00
nobody
b38bc8d848 This commit was manufactured by cvs2svn to create branch
'tmpw2001-paper'.

[SVN r10279]
2001-06-06 19:08:52 +00:00
Jeremy Siek
9c2549bd00 files for the tmpw2001 paper about iterator adaptors
[SVN r10278]
2001-06-06 19:08:51 +00:00
Dave Abrahams
b7c8e0c17f changes from Daryle Walker
[SVN r10264]
2001-06-04 11:57:37 +00:00
Jeremy Siek
dd3cfe1837 removed old arg ordering, use defaults instead
[SVN r10258]
2001-06-03 20:00:24 +00:00
Beman Dawes
43f525298e Remove compiler workarounds no longer needed due to BOOST_STATIC_ASSERT fix. For stylistic reasons, change sizeof() test to sizeof() != 0
[SVN r10236]
2001-05-28 14:22:30 +00:00
Beman Dawes
1bb1898ab9 Dave says qualifiers weren't really needed
[SVN r10222]
2001-05-24 19:11:51 +00:00
Beman Dawes
9578f24be9 Workaround compiler problems while waiting to find out if BOOST_STATIC_ASSERT is broken
[SVN r10218]
2001-05-24 16:02:42 +00:00
Jens Maurer
46fae3aed2 added check_delete workaround for Sun CC
[SVN r10213]
2001-05-24 09:26:48 +00:00
Beman Dawes
e35f91a70a Smart pointer and utility changes related to adding checked_delere and checked_array_delete
[SVN r10189]
2001-05-22 18:58:21 +00:00
John Maddock
851052fcca Updated docs - added VC6 bug warning
[SVN r10062]
2001-05-08 11:17:44 +00:00
John Maddock
5ef81b2952 Updated/stricter test program
[SVN r10061]
2001-05-08 11:17:05 +00:00
John Maddock
ef2851c053 Fixes for Sun C++ 5.1
[SVN r10060]
2001-05-08 11:16:35 +00:00
John Maddock
0b4387cff5 reorganised tests to show up VC6 bugs
[SVN r10002]
2001-05-02 10:59:32 +00:00
John Maddock
a40cf11fbf Rewritten compressed_pair regression script to test everything in a more methodical way
[SVN r10000]
2001-05-01 11:17:02 +00:00
Beman Dawes
5c495cd223 Change all eGroups references to YahooGroups
[SVN r9979]
2001-04-25 00:24:50 +00:00
Jeremy Siek
cf1296dff8 added stuff about Default Constructible needed for the function object
[SVN r9683]
2001-03-29 16:26:42 +00:00
Jeremy Siek
d6d88db6e8 std::bind1st -> boost::bind1st
[SVN r9682]
2001-03-29 16:19:34 +00:00
Jeremy Siek
85c2a35257 std::binder1st -> boost::binder1st
[SVN r9681]
2001-03-29 16:18:41 +00:00
Jeremy Siek
836d8b1c64 added spaces in name
[SVN r9673]
2001-03-29 04:08:38 +00:00
John Maddock
98d8c8ab71 fixed broken link
[SVN r9645]
2001-03-27 10:54:12 +00:00
Jeremy Siek
db45013339 fixed sgi stl link
[SVN r9631]
2001-03-22 16:06:15 +00:00
Jeremy Siek
a55c37e7f6 fixed sgi stl links
[SVN r9630]
2001-03-22 16:05:48 +00:00
Jeremy Siek
46a270fcca fixed link to sgi stl
[SVN r9629]
2001-03-22 16:02:11 +00:00
Jeremy Siek
967856518e updated link to sgi stl
[SVN r9628]
2001-03-22 16:01:18 +00:00
Jeremy Siek
7f93e739fe added documentation for initialize() policy function
[SVN r9592]
2001-03-19 21:46:14 +00:00
Jeremy Siek
2cd1422514 added comment about abstract base classes as value_type
[SVN r9584]
2001-03-19 17:31:27 +00:00
Beman Dawes
feb370b201 1.21.0 run up including fixing broken links
[SVN r9523]
2001-03-09 14:36:41 +00:00
Dave Abrahams
d1b34e64d8 Fixes for validator.w3.org
[SVN r9518]
2001-03-09 03:28:13 +00:00
Dave Abrahams
b9a1eead40 Mostly clarification. Fix: changed "category" to "iterator_category" in one place.
[SVN r9517]
2001-03-09 03:10:32 +00:00
Jeremy Siek
1e4bfac98c added named template parameter to table of contents
[SVN r9510]
2001-03-08 21:36:09 +00:00
Jeremy Siek
3bb504fbf3 added revision history line
[SVN r9506]
2001-03-08 20:50:14 +00:00
Jeremy Siek
5029791c90 split off indirect and transform tests into separate files
[SVN r9505]
2001-03-08 20:49:05 +00:00
Beman Dawes
a1a68f0970 1.21.0 run up
[SVN r9502]
2001-03-08 20:35:52 +00:00
Jeremy Siek
f8543d79eb added more static asserts
[SVN r9500]
2001-03-08 20:02:00 +00:00
Jeremy Siek
f353415136 added docs for iterator_traits_generator
[SVN r9498]
2001-03-08 19:19:46 +00:00
Jeremy Siek
26240403b0 added a test to make sure that the type set by the generator is really the
type used


[SVN r9497]
2001-03-08 19:04:29 +00:00
Jeremy Siek
3a39729b58 new file
[SVN r9488]
2001-03-08 16:33:40 +00:00
Dave Abrahams
096c961d9a Patches for Intel C++
[SVN r9425]
2001-03-04 16:08:20 +00:00
Dave Abrahams
01fe04a6a2 Workaround for Borland
[SVN r9424]
2001-03-04 16:07:11 +00:00
John Maddock
7ea4014993 Misc fixes that missed the last commit..
[SVN r9402]
2001-03-04 11:08:29 +00:00
Beman Dawes
d50b374f88 Boost Test Library initial commit
[SVN r9364]
2001-02-28 21:39:56 +00:00
Jeremy Siek
27dfb25570 added function output iterator adaptor
[SVN r9351]
2001-02-27 05:50:51 +00:00
John Maddock
b5ed77985e added missing typename's to docs
[SVN r9324]
2001-02-25 12:04:48 +00:00
John Maddock
61243bd15f type_traits: more tentative EDG compiler fixes...
[SVN r9321]
2001-02-24 13:04:56 +00:00
Dave Abrahams
368b94d804 Corrected numeric_limits<>::is_integral -> numeric_limits<>::is_integer
[SVN r9299]
2001-02-20 23:15:29 +00:00
Jeremy Siek
a5adbbfd5f use filter_iter::policies_type instead of filter_gen::policies_type
[SVN r9292]
2001-02-20 16:01:00 +00:00
John Maddock
a19d13f123 More type_traits tweeks.
[SVN r9287]
2001-02-20 12:17:55 +00:00
Dave Abrahams
78886ab383 Added cross-reference; improved policies documentation
[SVN r9286]
2001-02-20 03:49:26 +00:00
Dave Abrahams
168012b465 Describe const/mutable interactions and give rationale for no
reverse_iterator_pair_generator.


[SVN r9285]
2001-02-20 03:04:03 +00:00
Dave Abrahams
d9d58ea66e Take advantage of improved iterator_traits to do more tests on MSVC. Reordered
some #ifdefs for coherency.


[SVN r9281]
2001-02-19 22:36:22 +00:00
Dave Abrahams
56f5f6e8d5 Take adavantage of improved iterator_traits to do more tests on MSVC. Hack
around an MSVC-with-STLport internal compiler error.


[SVN r9280]
2001-02-19 22:34:31 +00:00
Dave Abrahams
3cb6420eda Roll back the reverse_iterator_pair_generator test
[SVN r9278]
2001-02-19 20:37:24 +00:00
Dave Abrahams
60be2c1186 Added tests for reverse_iterator_pair_generator
[SVN r9273]
2001-02-19 16:21:12 +00:00
John Maddock
ed210f6b2c more type traits updates:
Header includes get BOOST_ prefix,
BOOST_DECL_MC dropped in favour of new BOOST_STATIC_CONSTANT (from config.hpp),
operator ! dropped in favour of boost::type_traits::ice_not template.


[SVN r9270]
2001-02-19 12:52:30 +00:00
Dave Abrahams
029bc59d74 Added some missing 'explicit's
[SVN r9265]
2001-02-18 22:23:13 +00:00
Dave Abrahams
961c08a82f Apply Jens' suggested fixes
[SVN r9263]
2001-02-18 21:50:57 +00:00
Jens Maurer
7ee484c614 fix minor typos
[SVN r9259]
2001-02-18 19:26:20 +00:00
Jens Maurer
05c6fbbf99 needs <boost/type_traits/same_traits.hpp>
[SVN r9253]
2001-02-18 15:19:23 +00:00
John Maddock
91078b7f7a type_traits: regression failure fixes from type traits changes...
[SVN r9249]
2001-02-18 11:43:01 +00:00
Jeremy Siek
20d804afc4 changes to order of indirect_iterator template parameter list, and
fixed a typo


[SVN r9247]
2001-02-17 22:03:30 +00:00
Jeremy Siek
c21f6d1cbf added Category parameter and made a few more edits with regards to type requirements
[SVN r9239]
2001-02-17 19:59:19 +00:00
John Maddock
393e79c1fd Added new type traits files.
[SVN r9238]
2001-02-17 12:25:45 +00:00
Jeremy Siek
8b92c8a085 adjusted requirements for value type of the base iterator
[SVN r9236]
2001-02-17 01:51:45 +00:00
Jeremy Siek
ff73dd94c9 made iterator_adaptor constructor explicit
[SVN r9235]
2001-02-17 01:50:40 +00:00
Jeremy Siek
af43904f38 added "explicit" to iterator_adaptor constructor
[SVN r9234]
2001-02-17 01:44:41 +00:00
Dave Abrahams
485074f265 Added a missing const. Made the tests run (somewhat) with plain MSVC again.
[SVN r9232]
2001-02-16 23:04:49 +00:00
Jens Maurer
2e0ee55b5e add missing my_int3::operator!=
[SVN r9231]
2001-02-16 21:28:59 +00:00
Jeremy Siek
e9105d32cb background color and a whitespace edit
[SVN r9228]
2001-02-16 16:38:45 +00:00
Dave Abrahams
964d23f68c Edits for clarity
[SVN r9224]
2001-02-16 05:51:37 +00:00
Dave Abrahams
be5aaaae7b More edits for clarity. Added const/non-const example.
[SVN r9223]
2001-02-16 05:33:21 +00:00
Dave Abrahams
bf13bd7b3f Massive edits
[SVN r9222]
2001-02-16 05:30:49 +00:00
Dave Abrahams
352e392fcb Checked and cleaned using HTML TIDY.
[SVN r9220]
2001-02-16 02:36:36 +00:00
Dave Abrahams
083b1b02df Bigtime edits
[SVN r9219]
2001-02-16 00:38:28 +00:00
Jeremy Siek
648c6240a2 added another link to the generic_programming.html#policies
[SVN r9218]
2001-02-15 16:57:12 +00:00
Jeremy Siek
60cab840cb removed strange ssh garbage
[SVN r9217]
2001-02-15 16:52:39 +00:00
Jeremy Siek
83a4380dab added mention of traits requirement under Type Requirements section
[SVN r9216]
2001-02-15 16:49:16 +00:00
Jeremy Siek
de84fe8d98 oops, meant to remove use of policies_type from filter_iterator_generator
in the last commit, but accidentally added it :(


[SVN r9215]
2001-02-15 16:43:54 +00:00
Jeremy Siek
ed3cbfdb8e removed policies_type from filter_iterator_generator
[SVN r9214]
2001-02-15 16:41:48 +00:00
Dave Abrahams
fda44ca17d General edits for clarity; some reorganization.
[SVN r9213]
2001-02-15 16:39:55 +00:00
Jeremy Siek
272025bb07 fixed my_int::operator--
[SVN r9208]
2001-02-15 06:47:06 +00:00
Jeremy Siek
8e92bcf1b2 removed policies_type from filter_iterator_generator
[SVN r9207]
2001-02-15 06:44:26 +00:00
Jeremy Siek
84f1ffdefe added section on Members to cover constructors, etc. and added
a section on Operators


[SVN r9206]
2001-02-15 06:41:46 +00:00
Jeremy Siek
7e25450054 added discusion of counting_iterator_traits, and added type requirements
for the Incrementable type.

added uses of user-defined types to the test


[SVN r9204]
2001-02-15 05:53:10 +00:00
Dave Abrahams
4a563fa266 added missing boost::
[SVN r9199]
2001-02-14 20:35:39 +00:00
Dave Abrahams
aa4c0ec000 Test new VC6 workarounds
[SVN r9198]
2001-02-13 23:32:19 +00:00
Jeremy Siek
e1ecfbdc43 added output for the transform iterator example
[SVN r9187]
2001-02-13 04:38:59 +00:00
Jeremy Siek
a4e122a82e changed template class to class template
[SVN r9186]
2001-02-13 04:34:44 +00:00
Jeremy Siek
93216e8fb7 copyright
[SVN r9184]
2001-02-13 04:25:24 +00:00
Jeremy Siek
16272c210d fixed typo
[SVN r9183]
2001-02-13 04:24:24 +00:00
Jeremy Siek
e104b00da1 merged in Dave's additions and added a tutorial using the implementation
of transform iterator as the example


[SVN r9182]
2001-02-13 04:15:17 +00:00
Jeremy Siek
ce5c6bcc08 removed use of istream_iterator for operator-> test, replaced with
use of concept archetypes


[SVN r9180]
2001-02-13 02:03:13 +00:00
Jeremy Siek
8694ce31fe changed int* to std::vector<int>::iterator
[SVN r9178]
2001-02-12 21:59:25 +00:00
Jeremy Siek
d960e5eadd added another example
[SVN r9177]
2001-02-12 21:57:19 +00:00
Jeremy Siek
2dc71e87a3 new files
[SVN r9176]
2001-02-12 21:35:20 +00:00
Jeremy Siek
6bf17edde2 updated url to the iterator_adaptor class
[SVN r9156]
2001-02-12 05:24:45 +00:00
Jeremy Siek
88573d515d fixed Reference and Pointer template paremeter descriptions
[SVN r9155]
2001-02-12 05:20:09 +00:00
Jeremy Siek
89b9f77823 obsolete and not needed
[SVN r9152]
2001-02-12 04:55:19 +00:00
Jeremy Siek
765d9be17d small edit
[SVN r9151]
2001-02-12 04:53:39 +00:00
Jeremy Siek
7135373008 various edits
[SVN r9150]
2001-02-12 04:52:24 +00:00
Jeremy Siek
ee269884fc finished 1st draft of reverse iterator docs
[SVN r9149]
2001-02-12 04:51:56 +00:00
Jeremy Siek
387540d5f1 using make_const_projection_iterator() for last example,
and a couple other minor edits


[SVN r9145]
2001-02-12 02:55:19 +00:00
Jeremy Siek
2eba7b42a8 new files
[SVN r9144]
2001-02-12 02:52:26 +00:00
Jeremy Siek
07115d26c7 finished 1st draft
[SVN r9143]
2001-02-12 01:50:50 +00:00
Jeremy Siek
c43ed815a0 new files
[SVN r9137]
2001-02-11 20:05:00 +00:00
Dave Abrahams
ff01e36d12 Compile with Borland, re-enable failing tests
[SVN r9136]
2001-02-11 19:53:56 +00:00
Dave Abrahams
ac4798b16c Final fixes for Borland
[SVN r9135]
2001-02-11 19:50:14 +00:00
Dave Abrahams
d4e14fed0e Fixed bugs in the iterator helpers which prevented explicitly supplied arguments from actually being used
[SVN r9128]
2001-02-11 19:31:21 +00:00
Jeremy Siek
5f91259344 few edits
[SVN r9125]
2001-02-11 19:26:26 +00:00
Jeremy Siek
20a9d9645d Added test of operator-> for forward and input iterators.
[SVN r9124]
2001-02-11 19:25:49 +00:00
Jeremy Siek
c86f6b4abd Dave's suggested edits
[SVN r9122]
2001-02-11 18:27:40 +00:00
Jeremy Siek
d66489b5b2 changed per Dave's comments
[SVN r9121]
2001-02-11 18:14:04 +00:00
Dave Abrahams
b743ee9f0c #if 0'd out use of counting_iterator on non-numeric types in MSVC without STLport, so that the other tests may proceed
[SVN r9120]
2001-02-11 16:19:17 +00:00
Dave Abrahams
95ba69c00a Borland fixes
[SVN r9119]
2001-02-11 16:16:53 +00:00
Dave Abrahams
2ac273739c Update for compatibility with new iterator_adaptor interface
[SVN r9118]
2001-02-11 16:14:14 +00:00
Dave Abrahams
5b4d28708c Fixes for Borland
[SVN r9117]
2001-02-11 16:13:38 +00:00
Dave Abrahams
4cc4383488 Some fixes for Borland get it closer on that compiler
[SVN r9112]
2001-02-11 16:05:01 +00:00
Jeremy Siek
8935232248 new files
[SVN r9109]
2001-02-11 05:25:19 +00:00
Jeremy Siek
5c6dd2f172 various edits
[SVN r9108]
2001-02-11 04:34:32 +00:00
Dave Abrahams
eeeb7ef5b9 Replaced some static_casts with explicit construction
[SVN r9107]
2001-02-11 03:12:04 +00:00
Dave Abrahams
2efc9c1178 Use new adaptors interface
[SVN r9105]
2001-02-11 03:07:55 +00:00
Jeremy Siek
a84c46f6e3 added another example
[SVN r9103]
2001-02-11 03:01:47 +00:00
Jeremy Siek
a5c3dcdd02 redid docs for the template parameters
[SVN r9102]
2001-02-11 02:55:38 +00:00
Jeremy Siek
46f7a75eb7 fixed bug in policy object constructor
[SVN r9101]
2001-02-11 02:40:02 +00:00
Jeremy Siek
94b6710c5b fixed bug in policy object construction
[SVN r9100]
2001-02-11 02:39:35 +00:00
Jeremy Siek
d8dd3da9ab small edit
[SVN r9099]
2001-02-11 02:38:08 +00:00
Jeremy Siek
803ced004a finished 1st draft
[SVN r9098]
2001-02-11 02:35:09 +00:00
Dave Abrahams
0ea7d36ad0 A fix for EDG
[SVN r9096]
2001-02-10 23:16:05 +00:00
Jeremy Siek
87aafab759 new file
[SVN r9094]
2001-02-10 22:33:43 +00:00
Dave Abrahams
994d310abd Use new filter_ interface.
[SVN r9090]
2001-02-10 20:11:42 +00:00
Beman Dawes
228cdcf05e All final 1.20.2 changes, including fixing broken hyperlinks
[SVN r9071]
2001-02-10 14:42:14 +00:00
Dave Abrahams
42598e352c Use new reverse_ and indirect_ interfaces. Replace BOOST_NO_STD_ITERATOR_TRAITS
with BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've normalized to core
compiler capabilities


[SVN r9067]
2001-02-10 00:38:08 +00:00
Jeremy Siek
36a9e4d1da fixed usage of indirect_iterator_pair_generator
[SVN r9053]
2001-02-09 05:45:10 +00:00
Jeremy Siek
456dfd0dea adjusted to changes in iterator_adaptors.hpp, added more
tests of make_xxx


[SVN r9051]
2001-02-09 05:26:48 +00:00
Jeremy Siek
155457e2b5 more work on default args and explicit templat args
[SVN r9049]
2001-02-09 04:40:42 +00:00
Dave Abrahams
b5c91485bf Use Jeremy's new make_reverse_iterator form; add more comprehensive
testing. Force-decay array function arguments to pointers.


[SVN r9047]
2001-02-09 03:32:59 +00:00
Dave Abrahams
c959cf7870 bug fixes
[SVN r9031]
2001-02-08 04:46:41 +00:00
Jeremy Siek
5878c88636 added indirect_iterator_pair_generator back in
[SVN r9026]
2001-02-08 03:35:03 +00:00
Jeremy Siek
ddcef2fb19 Added tests for the make_xxx_iterator() helper functions
[SVN r9025]
2001-02-08 03:08:09 +00:00
Dave Abrahams
493d124c07 rename counting_iterator() -> make_counting_iterator()
[SVN r9015]
2001-02-07 22:27:02 +00:00
Jens Maurer
f42060c616 add missing "typename"
[SVN r9005]
2001-02-07 17:51:55 +00:00
Dave Abrahams
834facc932 trivial flotsam cleanup
[SVN r9004]
2001-02-07 17:23:52 +00:00
Dave Abrahams
f82d0b76ee More comprehensive testing; factored out static tests for better reuse
[SVN r9001]
2001-02-07 16:38:41 +00:00
Jeremy Siek
c25d225275 Replaced use of xxx_pair_generator with xxx_generator where
possible (which was all but the projection iterator).


[SVN r8996]
2001-02-07 06:36:12 +00:00
Dave Abrahams
c503a274b5 Removed now-defaulted template arguments where possible
Updated names to correspond to new generator naming convention.
Added a trivial test for make_transform_iterator().
Gave traits for const iterators a mutable value_type, per std.
Resurrected my original tests for indirect iterators.


[SVN r8995]
2001-02-07 05:37:08 +00:00
Jeremy Siek
087069d215 added concept check for the default iterator policy
[SVN r8990]
2001-02-07 02:44:18 +00:00
Jeremy Siek
826a6dd114 changed test for transform iterator to use input_iterator instead of
random access iterator


[SVN r8937]
2001-02-04 23:46:31 +00:00
Dave Abrahams
f31483838d Fix for compilers without standard iterator_traits
[SVN r8929]
2001-02-04 20:11:30 +00:00
Dave Abrahams
d8a9b633d9 Fix for newly-corrected bidirectional_iterator_test requirements.
[SVN r8926]
2001-02-04 19:09:46 +00:00
Dave Abrahams
c060e4466a Added use of iterator_tests.hpp
[SVN r8923]
2001-02-04 18:26:43 +00:00
Jeremy Siek
a9951376f4 removed UDT -> int is_convertible test because the noncopyable -> int
test already brings out the g++ warning


[SVN r8834]
2001-01-31 19:08:27 +00:00
Jeremy Siek
bda0c8f5e3 added some more tests and fixed signature of main() so this will link
with MSVC


[SVN r8833]
2001-01-31 18:54:29 +00:00
Jeremy Siek
71902f23a2 Added test case for is_convertible with UDT that brings out the
warning message bug with g++.


[SVN r8821]
2001-01-31 02:12:08 +00:00
Dave Abrahams
dfd6c85569 Inital checkin
[SVN r8813]
2001-01-30 16:00:37 +00:00
Dave Abrahams
0e41b2cc1a Removed not_an_iterator detritus
[SVN r8808]
2001-01-29 02:14:44 +00:00
48 changed files with 9862 additions and 570 deletions

116
Assignable.html Normal file
View File

@@ -0,0 +1,116 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Assignable</Title>
</HEAD>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<!--end header-->
<BR Clear>
<H1>Assignable</H1>
<h3>Description</h3>
A type is Assignable if it is possible to assign one object of the type
to another object of that type.
<h3>Notation</h3>
<Table>
<TR>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
is type that is a model of Assignable
</TD>
</TR>
<TR>
<TD VAlign=top>
<tt>t</tt>
</TD>
<TD VAlign=top>
is an object of type <tt>T</tt>
</TD>
</tr>
<TR>
<TD VAlign=top>
<tt>u</tt>
</TD>
<TD VAlign=top>
is an object of type <tt>T</tt> or possibly <tt>const T</tt>
</TD>
</tr>
</table>
<h3>Definitions</h3>
<h3>Valid expressions</h3>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
<TH>
Semantics
</TH>
</TR>
<TR>
<TD VAlign=top>
Assignment
</TD>
<TD VAlign=top>
<tt>t = u</tt>
</TD>
<TD VAlign=top>
<tt>T&amp;</tt>
</TD>
<TD VAlign=top>
<tt>t</tt> is equivalent to <tt>u</tt>
</TD>
</TR>
</table>
</table>
<h3>Models</h3>
<UL>
<LI><tt>int</tt>
<LI><tt>std::pair</tt>
</UL>
<h3>See also</h3>
<a href="http://www.sgi.com/tech/stl/DefaultConstructible.html">DefaultConstructible</A>
and
<A href="./CopyConstructible.html">CopyConstructible</A>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

210
CopyConstructible.html Normal file
View File

@@ -0,0 +1,210 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Copy Constructible</Title>
</HEAD>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<!--end header-->
<BR Clear>
<H1>Copy Constructible</H1>
<h3>Description</h3>
A type is Copy Constructible if it is possible to copy objects of that
type.
<h3>Notation</h3>
<Table>
<TR>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
is type that is a model of Copy Constructible
</TD>
</TR>
<TR>
<TD VAlign=top>
<tt>t</tt>
</TD>
<TD VAlign=top>
is an object of type <tt>T</tt>
</TD>
</tr>
<TR>
<TD VAlign=top>
<tt>u</tt>
</TD>
<TD VAlign=top>
is an object of type <tt>const T</tt>
</TD>
</tr>
</table>
<h3>Definitions</h3>
<h3>Valid expressions</h3>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Return type
</TH>
<TH>
Semantics
</TH>
</TR>
<TR>
<TD VAlign=top>
Copy constructor
</TD>
<TD VAlign=top>
<tt>T(t)</tt>
</TD>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
<tt>t</tt> is equivalent to <tt>T(t)</tt>
</TD>
</TR>
<TR>
<TD VAlign=top>
Copy constructor
</TD>
<TD VAlign=top>
<pre>
T(u)
</pre>
</TD>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
<tt>u</tt> is equivalent to <tt>T(u)</tt>
</TD>
</TR>
<TR>
<TD VAlign=top>
Destructor
</TD>
<TD VAlign=top>
<pre>
t.~T()
</pre>
</TD>
<TD VAlign=top>
<tt>T</tt>
</TD>
<TD VAlign=top>
&nbsp;
</TD>
</TR>
<TR>
<TD VAlign=top>
Address Operator
</TD>
<TD VAlign=top>
<pre>
&amp;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>
&amp;u
</pre>
</TD>
<TD VAlign=top>
<tt>T*</tt>
</TD>
<TD VAlign=top>
denotes the address of <tt>u</tt>
</TD>
</TR>
</table>
</table>
<h3>Models</h3>
<UL>
<LI><tt>int</tt>
<LI><tt>std::pair</tt>
</UL>
<h3>Concept Checking Class</h3>
<pre>
template &lt;class T&gt;
struct CopyConstructibleConcept
{
void constraints() {
T a(b); // require copy constructor
T* ptr = &amp;a; // require address of operator
const_constraints(a);
ignore_unused_variable_warning(ptr);
}
void const_constraints(const T&amp; a) {
T c(a); // require const copy constructor
const T* ptr = &amp;a; // require const address of operator
ignore_unused_variable_warning(c);
ignore_unused_variable_warning(ptr);
}
T b;
};
</pre>
<h3>See also</h3>
<A
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default Constructible</A>
and
<A hrefa="./Assignable.html">Assignable</A>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 2000</TD><TD>
<A HREF=http://www.lsc.nd.edu/~jsiek>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

212
LessThanComparable.html Normal file
View File

@@ -0,0 +1,212 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<!--
-- Copyright (c) 1996-1999
-- Silicon Graphics Computer Systems, Inc.
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
--
-- Copyright (c) 1994
-- Hewlett-Packard Company
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Hewlett-Packard Company makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
--
-->
<Head>
<Title>LessThanComparable</Title>
</Head>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<!--end header-->
<BR Clear>
<H1>LessThanComparable</H1>
<h3>Description</h3>
A type is LessThanComparable if it is ordered: it must
be possible to compare two objects of that type using <tt>operator&lt;</tt>, and
<tt>operator&lt;</tt> must be a strict weak ordering relation.
<h3>Refinement of</h3>
<h3>Associated types</h3>
<h3>Notation</h3>
<Table>
<TR>
<TD VAlign=top>
<tt>X</tt>
</TD>
<TD VAlign=top>
A type that is a model of LessThanComparable
</TD>
</TR>
<TR>
<TD VAlign=top>
<tt>x</tt>, <tt>y</tt>, <tt>z</tt>
</TD>
<TD VAlign=top>
Object of type <tt>X</tt>
</TD>
</tr>
</table>
<h3>Definitions</h3>
Consider the relation <tt>!(x &lt; y) &amp;&amp; !(y &lt; x)</tt>. If this relation is
transitive (that is, if <tt>!(x &lt; y) &amp;&amp; !(y &lt; x) &amp;&amp; !(y &lt; z) &amp;&amp; !(z &lt; y)</tt>
implies <tt>!(x &lt; z) &amp;&amp; !(z &lt; x)</tt>), then it satisfies the mathematical
definition of an equivalence relation. In this case, <tt>operator&lt;</tt>
is a <i>strict weak ordering</i>.
<P>
If <tt>operator&lt;</tt> is a strict weak ordering, and if each equivalence class
has only a single element, then <tt>operator&lt;</tt> is a <i>total ordering</i>.
<h3>Valid expressions</h3>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Type requirements
</TH>
<TH>
Return type
</TH>
</TR>
<TR>
<TD VAlign=top>
Less
</TD>
<TD VAlign=top>
<tt>x &lt; y</tt>
</TD>
<TD VAlign=top>
&nbsp;
</TD>
<TD VAlign=top>
Convertible to <tt>bool</tt>
</TD>
</TR>
</table>
<h3>Expression semantics</h3>
<Table border>
<TR>
<TH>
Name
</TH>
<TH>
Expression
</TH>
<TH>
Precondition
</TH>
<TH>
Semantics
</TH>
<TH>
Postcondition
</TH>
</TR>
<TR>
<TD VAlign=top>
Less
</TD>
<TD VAlign=top>
<tt>x &lt; y</tt>
</TD>
<TD VAlign=top>
<tt>x</tt> and <tt>y</tt> are in the domain of <tt>&lt;</tt>
</TD>
<TD VAlign=top>
&nbsp;
</TD>
</table>
<h3>Complexity guarantees</h3>
<h3>Invariants</h3>
<Table border>
<TR>
<TD VAlign=top>
Irreflexivity
</TD>
<TD VAlign=top>
<tt>x &lt; x</tt> must be false.
</TD>
</TR>
<TR>
<TD VAlign=top>
Antisymmetry
</TD>
<TD VAlign=top>
<tt>x &lt; y</tt> implies !(y &lt; x) <A href="#2">[2]</A>
</TD>
</TR>
<TR>
<TD VAlign=top>
Transitivity
</TD>
<TD VAlign=top>
<tt>x &lt; y</tt> and <tt>y &lt; z</tt> implies <tt>x &lt; z</tt> <A href="#3">[3]</A>
</TD>
</tr>
</table>
<h3>Models</h3>
<UL>
<LI>
int
</UL>
<h3>Notes</h3>
<P><A name="1">[1]</A>
Only <tt>operator&lt;</tt> is fundamental; the other inequality operators
are essentially syntactic sugar.
<P><A name="2">[2]</A>
Antisymmetry is a theorem, not an axiom: it follows from
irreflexivity and transitivity.
<P><A name="3">[3]</A>
Because of irreflexivity and transitivity, <tt>operator&lt;</tt> always
satisfies the definition of a <i>partial ordering</i>. The definition of
a <i>strict weak ordering</i> is stricter, and the definition of a
<i>total ordering</i> is stricter still.
<h3>See also</h3>
<A href="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</A>, <A href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">StrictWeakOrdering</A>
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 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>

View File

@@ -0,0 +1,92 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. Silicon Graphics makes no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>MultiPassInputIterator</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<BR Clear>
<H2>
<A NAME="concept:MultiPassInputIterator"></A>
Multi-Pass Input Iterator
</H2>
This concept is a refinement of <a
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>,
adding the requirements that the iterator can be used to make multiple
passes through a range, and that if <TT>it1 == it2</TT> and
<TT>it1</TT> is dereferenceable then <TT>++it1 == ++it2</TT>. The
Multi-Pass Input Iterator is very similar to the <a
href="http://www.sgi.com/tech/stl/ForwardIterator.hmtl">Forward Iterator</a>. The
only difference is that a <a
href="http://www.sgi.com/tech/stl/ForwardIterator.hmtl">Forward Iterator</a>
requires the <TT>reference</TT> type to be <TT>value_type&amp;</TT>, whereas
MultiPassInputIterator is like <a
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>
in that the <TT>reference</TT> type merely has to be convertible to
<TT>value_type</TT>.
<h3>Design Notes</h3>
comments by Valentin Bonnard:
<p> I think that introducing Multi-Pass Input Iterator isn't the right
solution. Do you also want to define Multi-Pass Bidirectionnal Iterator
and Multi-Pass Random Access Iterator ? I don't, definitly. It only
confuses the issue. The problem lies into the existing hierarchy of
iterators, which mixes movabillity, modifiabillity and lvalue-ness,
and these are clearly independant.
<p> The terms Forward, Bidirectionnal and Random Access are about
movabillity and shouldn't be used to mean anything else. In a
completly orthogonal way, iterators can be immutable, mutable, or
neither. Lvalueness of iterators is also orthogonal with
immutabillity. With these clean concepts, your Multi-Pass Input Iterator
is just called a Forward Iterator.
<p>
Other translations are:<br>
std::Forward Iterator -> ForwardIterator & Lvalue Iterator<br>
std::Bidirectionnal Iterator -> Bidirectionnal Iterator & Lvalue Iterator<br>
std::Random Access Iterator -> Random Access Iterator & Lvalue Iterator<br>
<p>
Note that in practice the only operation not allowed on my
Forward Iterator which is allowed on std::Forward Iterator is
<tt>&*it</tt>. I think that <tt>&*</tt> is rarely needed in generic code.
<p>
reply by Jeremy Siek:
<p>
The above analysis by Valentin is right on. Of course, there is
the problem with backward compatibility. The current STL implementations
are based on the old definition of Forward Iterator. The right course
of action is to get Forward Iterator, etc. changed in the C++ standard.
Once that is done we can drop Multi-Pass Input Iterator.
<br>
<HR>
<TABLE>
<TR valign=top>
<TD nowrap>Copyright &copy 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>

View File

@@ -5,7 +5,7 @@
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">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<title>Call Traits</title>
</head>
@@ -751,7 +751,7 @@ 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>
discussion list at <a href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>.</p>
<p>.</p>

380
call_traits_test.cpp Normal file
View File

@@ -0,0 +1,380 @@
// boost::compressed_pair test program
// (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// standalone test program for <boost/call_traits.hpp>
// 03 Oct 2000:
// Enabled extra tests for VC6.
#include <cassert>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <typeinfo>
#include <boost/call_traits.hpp>
#include <boost/type_traits/type_traits_test.hpp>
//
// struct contained models a type that contains a type (for example std::pair)
// arrays are contained by value, and have to be treated as a special case:
//
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 call_traits_checker:
// verifies behaviour of contained example:
//
template <class T>
struct call_traits_checker
{
typedef typename boost::call_traits<T>::param_type param_type;
void operator()(param_type);
};
template <class T>
void call_traits_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());
#ifndef __ICL
//cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained<T>::value).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained<T>::get).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained<T>::const_get).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained<T>::call).name() << endl;
cout << endl;
#endif
}
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T, std::size_t N>
struct call_traits_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 comparible_UDT
{
int i_;
comparible_UDT() : i_(2){}
bool operator == (const comparible_UDT& v){ return v.i_ == i_; }
};
int main(int argc, char *argv[ ])
{
call_traits_checker<comparible_UDT> c1;
comparible_UDT u;
c1(u);
call_traits_checker<int> c2;
int i = 2;
c2(i);
int* pi = &i;
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
call_traits_checker<int*> c3;
c3(pi);
call_traits_checker<int&> c4;
c4(i);
call_traits_checker<const int&> c5;
c5(i);
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
int a[2] = {1,2};
call_traits_checker<int[2]> c6;
c6(a);
#endif
#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(comparible_UDT, boost::call_traits<comparible_UDT>::value_type)
type_test(comparible_UDT&, boost::call_traits<comparible_UDT>::reference)
type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::const_reference)
type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::param_type)
type_test(int, boost::call_traits<int>::value_type)
type_test(int&, boost::call_traits<int>::reference)
type_test(const int&, boost::call_traits<int>::const_reference)
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)
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
type_test(int&, boost::call_traits<int&>::value_type)
type_test(int&, boost::call_traits<int&>::reference)
type_test(const int&, boost::call_traits<int&>::const_reference)
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)
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
type_test(const int*, boost::call_traits<int[3]>::value_type)
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
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 8 tests (8 errors)" << std::endl;
failures += 8;
test_count += 8;
#endif
#else
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
failures += 20;
test_count += 20;
#endif
return check_result(argc, argv);
}
//
// 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(typename 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*>;
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
template struct call_traits_test<int&>;
template struct call_traits_test<const int&>;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template struct call_traits_test<int[2], true>;
#endif
#endif
#ifdef BOOST_MSVC
unsigned int expected_failures = 10;
#elif defined(__SUNPRO_CC)
unsigned int expected_failures = 11;
#elif defined(__BORLANDC__)
unsigned int expected_failures = 2;
#elif defined(__GNUC__)
unsigned int expected_failures = 4;
#else
unsigned int expected_failures = 0;
#endif

31
checked_delete_test.cpp Normal file
View File

@@ -0,0 +1,31 @@
// Boost checked_delete test program ---------------------------------------//
// (C) Copyright Beman Dawes 2001. Permission to copy, use, modify, sell
// and distribute this software is granted provided this copyright
// notice appears in all copies. This software is provided "as is" without
// express or implied warranty, and with no claim as to its suitability for
// any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 21 May 01 Initial version (Beman Dawes)
#include <boost/utility.hpp> // for checked_delete
// This program demonstrates compiler errors when trying to delete an
// incomplete type.
namespace
{
class Incomplete;
}
int main()
{
Incomplete * p;
boost::checked_delete(p); // should cause compile time error
Incomplete ** pa;
boost::checked_array_delete(pa); // should cause compile time error
return 0;
} // main

98
compressed_pair.htm Normal file
View File

@@ -0,0 +1,98 @@
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="Template"
content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title>Header </title>
<boost/compressed_pair.hpp>
</head>
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF"
vlink="#800080">
<h2><img src="../../c++boost.gif" width="276" height="86">Header
&lt;<a href="../../boost/detail/compressed_pair.hpp">boost/compressed_pair.hpp</a>&gt;</h2>
<p>All of the contents of &lt;boost/compressed_pair.hpp&gt; 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
&quot;empty member optimisation&quot; is applied to compress the
size of the pair.</p>
<pre>template &lt;class T1, class T2&gt;
class compressed_pair
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits&lt;first_type&gt;::param_type first_param_type;
typedef typename call_traits&lt;second_type&gt;::param_type second_param_type;
typedef typename call_traits&lt;first_type&gt;::reference first_reference;
typedef typename call_traits&lt;second_type&gt;::reference second_reference;
typedef typename call_traits&lt;first_type&gt;::const_reference first_const_reference;
typedef typename call_traits&lt;second_type&gt;::const_reference second_const_reference;
compressed_pair() : base() {}
compressed_pair(first_param_type x, second_param_type y);
explicit compressed_pair(first_param_type x);
explicit compressed_pair(second_param_type y);
compressed_pair&amp; operator=(const compressed_pair&amp;);
first_reference first();
first_const_reference first() const;
second_reference second();
second_const_reference second() const;
void swap(compressed_pair&amp; y);
};</pre>
<p>The two members of the pair can be accessed using the member
functions first() and second(). Note that not all member
functions can be instantiated for all template parameter types.
In particular compressed_pair can be instantiated for reference
and array types, however in these cases the range of constructors
that can be used are limited. If types T1 and T2 are the same
type, then there is only one version of the single-argument
constructor, and this constructor initialises both values in the
pair to the passed value.</p>
<p>Note that compressed_pair can not be instantiated if either of
the template arguments is a union type, unless there is compiler
support for boost::is_union, or if boost::is_union is specialised
for the union type.</p>
<p>Finally, a word of caution for Visual C++ 6 users: if either
argument is an empty type, then assigning to that member will
produce memory corruption, unless the empty type has a &quot;do
nothing&quot; assignment operator defined. This is due to a bug
in the way VC6 generates implicit assignment operators.</p>
<hr>
<p>Revised 08 May 2001</p>
<p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided
&quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose.</p>
<p>Based on contributions by Steve Cleary, Beman Dawes, Howard
Hinnant and John Maddock.</p>
<p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John
Maddock</a>, the latest version of this file can be found at <a
href="http://www.boost.org">www.boost.org</a>, and the boost
discussion list at <a
href="http://www.yahoogroups.com/list/boost">www.yahoogroups.com/list/boost</a>.</p>
<p>&nbsp;</p>
</body>
</html>

401
compressed_pair_test.cpp Normal file
View File

@@ -0,0 +1,401 @@
// 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>
// Revised 03 Oct 2000:
// Enabled tests for VC6.
#include <iostream>
#include <typeinfo>
#include <cassert>
#include <boost/compressed_pair.hpp>
#include <boost/type_traits/type_traits_test.hpp>
#define BOOST_INCLUDE_MAIN
#include <boost/test/test_tools.hpp>
using namespace boost;
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
}
struct non_empty1
{
int i;
non_empty1() : i(1){}
non_empty1(int v) : i(v){}
friend bool operator==(const non_empty1& a, const non_empty1& b)
{ return a.i == b.i; }
};
struct non_empty2
{
int i;
non_empty2() : i(3){}
non_empty2(int v) : i(v){}
friend bool operator==(const non_empty2& a, const non_empty2& b)
{ return a.i == b.i; }
};
#ifdef __GNUC__
using std::swap;
#endif
template <class T1, class T2>
struct compressed_pair_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
#ifndef __GNUC__
// gcc 2.90 can't cope with function scope using
// declarations, and generates an internal compiler error...
using std::swap;
#endif
// default construct:
boost::compressed_pair<T1,T2> cp1;
// first param construct:
boost::compressed_pair<T1,T2> cp2(p1);
cp2.second() = p2;
BOOST_TEST(cp2.first() == p1);
BOOST_TEST(cp2.second() == p2);
// second param construct:
boost::compressed_pair<T1,T2> cp3(p2);
cp3.first() = p1;
BOOST_TEST(cp3.second() == p2);
BOOST_TEST(cp3.first() == p1);
// both param construct:
boost::compressed_pair<T1,T2> cp4(p1, p2);
BOOST_TEST(cp4.first() == p1);
BOOST_TEST(cp4.second() == p2);
boost::compressed_pair<T1,T2> cp5(p3, p4);
BOOST_TEST(cp5.first() == p3);
BOOST_TEST(cp5.second() == p4);
// check const members:
const boost::compressed_pair<T1,T2>& cpr1 = cp4;
BOOST_TEST(cpr1.first() == p1);
BOOST_TEST(cpr1.second() == p2);
// copy construct:
boost::compressed_pair<T1,T2> cp6(cp4);
BOOST_TEST(cp6.first() == p1);
BOOST_TEST(cp6.second() == p2);
// assignment:
cp1 = cp4;
BOOST_TEST(cp1.first() == p1);
BOOST_TEST(cp1.second() == p2);
cp1 = cp5;
BOOST_TEST(cp1.first() == p3);
BOOST_TEST(cp1.second() == p4);
// swap:
cp4.swap(cp5);
BOOST_TEST(cp4.first() == p3);
BOOST_TEST(cp4.second() == p4);
BOOST_TEST(cp5.first() == p1);
BOOST_TEST(cp5.second() == p2);
swap(cp4,cp5);
BOOST_TEST(cp4.first() == p1);
BOOST_TEST(cp4.second() == p2);
BOOST_TEST(cp5.first() == p3);
BOOST_TEST(cp5.second() == p4);
}
//
// tests for case where one or both
// parameters are reference types:
//
template <class T1, class T2>
struct compressed_pair_reference_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_reference_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
#ifndef __GNUC__
// gcc 2.90 can't cope with function scope using
// declarations, and generates an internal compiler error...
using std::swap;
#endif
// both param construct:
boost::compressed_pair<T1,T2> cp4(p1, p2);
BOOST_TEST(cp4.first() == p1);
BOOST_TEST(cp4.second() == p2);
boost::compressed_pair<T1,T2> cp5(p3, p4);
BOOST_TEST(cp5.first() == p3);
BOOST_TEST(cp5.second() == p4);
// check const members:
const boost::compressed_pair<T1,T2>& cpr1 = cp4;
BOOST_TEST(cpr1.first() == p1);
BOOST_TEST(cpr1.second() == p2);
// copy construct:
boost::compressed_pair<T1,T2> cp6(cp4);
BOOST_TEST(cp6.first() == p1);
BOOST_TEST(cp6.second() == p2);
// assignment:
// VC6 bug:
// When second() is an empty class, VC6 performs the
// assignment by doing a memcpy - even though the empty
// class is really a zero sized base class, the result
// is that the memory of first() gets trampled over.
// Similar arguments apply to the case that first() is
// an empty base class.
// Strangely the problem is dependent upon the compiler
// settings - some generate the problem others do not.
cp4.first() = p3;
cp4.second() = p4;
BOOST_TEST(cp4.first() == p3);
BOOST_TEST(cp4.second() == p4);
}
//
// supplimentary tests for case where first arg only is a reference type:
//
template <class T1, class T2>
struct compressed_pair_reference1_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_reference1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// first param construct:
boost::compressed_pair<T1,T2> cp2(p1);
cp2.second() = p2;
BOOST_TEST(cp2.first() == p1);
BOOST_TEST(cp2.second() == p2);
#endif
}
//
// supplimentary tests for case where second arg only is a reference type:
//
template <class T1, class T2>
struct compressed_pair_reference2_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_reference2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// second param construct:
boost::compressed_pair<T1,T2> cp3(p2);
cp3.first() = p1;
BOOST_TEST(cp3.second() == p2);
BOOST_TEST(cp3.first() == p1);
#endif
}
//
// tests for where one or the other parameter is an array:
//
template <class T1, class T2>
struct compressed_pair_array1_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_array1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
// default construct:
boost::compressed_pair<T1,T2> cp1;
// second param construct:
boost::compressed_pair<T1,T2> cp3(p2);
cp3.first()[0] = p1[0];
BOOST_TEST(cp3.second() == p2);
BOOST_TEST(cp3.first()[0] == p1[0]);
// check const members:
const boost::compressed_pair<T1,T2>& cpr1 = cp3;
BOOST_TEST(cpr1.first()[0] == p1[0]);
BOOST_TEST(cpr1.second() == p2);
BOOST_TEST(sizeof(T1) == sizeof(cp1.first()));
}
template <class T1, class T2>
struct compressed_pair_array2_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_array2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
// default construct:
boost::compressed_pair<T1,T2> cp1;
// first param construct:
boost::compressed_pair<T1,T2> cp2(p1);
cp2.second()[0] = p2[0];
BOOST_TEST(cp2.first() == p1);
BOOST_TEST(cp2.second()[0] == p2[0]);
// check const members:
const boost::compressed_pair<T1,T2>& cpr1 = cp2;
BOOST_TEST(cpr1.first() == p1);
BOOST_TEST(cpr1.second()[0] == p2[0]);
BOOST_TEST(sizeof(T2) == sizeof(cp1.second()));
}
template <class T1, class T2>
struct compressed_pair_array_tester
{
// define the types we need:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
// define our test proc:
static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4);
};
template <class T1, class T2>
void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
{
// default construct:
boost::compressed_pair<T1,T2> cp1;
cp1.first()[0] = p1[0];
cp1.second()[0] = p2[0];
BOOST_TEST(cp1.first()[0] == p1[0]);
BOOST_TEST(cp1.second()[0] == p2[0]);
// check const members:
const boost::compressed_pair<T1,T2>& cpr1 = cp1;
BOOST_TEST(cpr1.first()[0] == p1[0]);
BOOST_TEST(cpr1.second()[0] == p2[0]);
BOOST_TEST(sizeof(T1) == sizeof(cp1.first()));
BOOST_TEST(sizeof(T2) == sizeof(cp1.second()));
}
int test_main(int argc, char *argv[ ])
{
// declare some variables to pass to the tester:
non_empty1 ne1(2);
non_empty1 ne2(3);
non_empty2 ne3(4);
non_empty2 ne4(5);
empty_POD_UDT e1;
empty_UDT e2;
// T1 != T2, both non-empty
compressed_pair_tester<non_empty1,non_empty2>::test(ne1, ne3, ne2, ne4);
// T1 != T2, T2 empty
compressed_pair_tester<non_empty1,empty_POD_UDT>::test(ne1, e1, ne2, e1);
// T1 != T2, T1 empty
compressed_pair_tester<empty_POD_UDT,non_empty2>::test(e1, ne3, e1, ne4);
// T1 != T2, both empty
compressed_pair_tester<empty_POD_UDT,empty_UDT>::test(e1, e2, e1, e2);
// T1 == T2, both non-empty
compressed_pair_tester<non_empty1,non_empty1>::test(ne1, ne1, ne2, ne2);
// T1 == T2, both empty
compressed_pair_tester<empty_UDT,empty_UDT>::test(e2, e2, e2, e2);
// test references:
// T1 != T2, both non-empty
compressed_pair_reference_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4);
compressed_pair_reference_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4);
compressed_pair_reference1_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4);
compressed_pair_reference2_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4);
// T1 != T2, T2 empty
compressed_pair_reference_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1);
compressed_pair_reference1_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1);
// T1 != T2, T1 empty
compressed_pair_reference_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4);
compressed_pair_reference2_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4);
// T1 == T2, both non-empty
compressed_pair_reference_tester<non_empty1&,non_empty1&>::test(ne1, ne1, ne2, ne2);
// tests arrays:
non_empty1 nea1[2];
non_empty1 nea2[2];
non_empty2 nea3[2];
non_empty2 nea4[2];
nea1[0] = non_empty1(5);
nea2[0] = non_empty1(6);
nea3[0] = non_empty2(7);
nea4[0] = non_empty2(8);
// T1 != T2, both non-empty
compressed_pair_array1_tester<non_empty1[2],non_empty2>::test(nea1, ne3, nea2, ne4);
compressed_pair_array2_tester<non_empty1,non_empty2[2]>::test(ne1, nea3, ne2, nea4);
compressed_pair_array_tester<non_empty1[2],non_empty2[2]>::test(nea1, nea3, nea2, nea4);
// T1 != T2, T2 empty
compressed_pair_array1_tester<non_empty1[2],empty_POD_UDT>::test(nea1, e1, nea2, e1);
// T1 != T2, T1 empty
compressed_pair_array2_tester<empty_POD_UDT,non_empty2[2]>::test(e1, nea3, e1, nea4);
// T1 == T2, both non-empty
compressed_pair_array_tester<non_empty1[2],non_empty1[2]>::test(nea1, nea1, nea2, nea2);
return 0;
}
unsigned int expected_failures = 0;

325
counting_iterator.htm Normal file
View File

@@ -0,0 +1,325 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Counting Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Counting Iterator Adaptor</h1>
Defined in header
<a href="../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a>
<p>
How would you fill up a vector with the numbers zero
through one hundred using <a
href="http://www.sgi.com/tech/stl/copy.html"><tt>std::copy()</tt></a>? The
only iterator operation missing from builtin integer types is an
<tt>operator*()</tt> that returns the current
value of the integer. The counting iterator adaptor adds this crucial piece of
functionality to whatever type it wraps. One can use the
counting iterator adaptor not only with integer types, but with any
type that is <tt>Incrementable</tt> (see type requirements <a href="#requirements">below</a>). The
following <b>pseudo-code</b> shows the general idea of how the
counting iterator is implemented.
</p>
<pre>
// inside a hypothetical counting_iterator class...
typedef Incrementable value_type;
value_type counting_iterator::operator*() const {
return this->base; // no dereference!
}
</pre>
All of the other operators of the counting iterator behave in the same
fashion as the <tt>Incrementable</tt> base type.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class Incrementable&gt;
struct <a href="#counting_iterator_traits">counting_iterator_traits</a>;
template &lt;class Incrementable&gt;
struct <a href="#counting_iterator_generator">counting_iterator_generator</a>;
template &lt;class Incrementable&gt;
typename counting_iterator_generator&lt;Incrementable&gt;::type
<a href="#make_counting_iterator">make_counting_iterator</a>(Incrementable x);
}
</pre>
<hr>
<h2><a name="counting_iterator_generator">The Counting Iterator Type
Generator</a></h2>
The class template <tt>counting_iterator_generator&lt;Incrementable&gt;</tt> is a <a href="../../more/generic_programming.html#type_generator">type generator</a> for counting iterators.
<pre>
template &lt;class Incrementable&gt;
class counting_iterator_generator
{
public:
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt; type;
};
</pre>
<h3>Example</h3>
In this example we use the counting iterator generator to create a
counting iterator, and count from zero to four.
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;iostream&gt;
#include &lt;boost/counting_iterator.hpp&gt;
int main(int, char*[])
{
// Example of using counting_iterator_generator
std::cout &lt;&lt; "counting from 0 to 4:" &lt;&lt; std::endl;
boost::counting_iterator_generator&lt;int&gt;::type first(0), last(4);
std::copy(first, last, std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
The output from this part is:
<pre>
counting from 0 to 4:
0 1 2 3
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><tt>Incrementable</tt></TD>
<TD>The type being wrapped by the adaptor.</TD>
</TR>
</Table>
<h3>Model of</h3>
If the <tt>Incrementable</tt> type has all of the functionality of a
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> except the <tt>operator*()</tt>, then the counting
iterator will be a model of <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a>. If the <tt>Incrementable</tt> type has less
functionality, then the counting iterator will have correspondingly
less functionality.
<h3><a name="requirements">Type Requirements</a></h3>
The <tt>Incrementable</tt> type must be <a
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default
Constructible</a>, <a href="./CopyConstructible.html">Copy
Constructible</a>, and <a href="./Assignable.html">Assignable</a>.
Also, the <tt>Incrementable</tt> type must provide access to an
associated <tt>difference_type</tt> and <tt>iterator_category</tt>
through the <a
href="#counting_iterator_traits"><tt>counting_iterator_traits</tt></a>
class.
<p>
Furthermore, if you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward
Iterator</a>, then the following expressions must be valid:
<pre>
Incrementable i, j;
++i // pre-increment
i == j // operator equal
</pre>
If you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
Bidirectional Iterator</a>, then pre-decrement is also required:
<pre>
--i
</pre>
If you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> Random
Access Iterator</a>, then these additional expressions are also required:
<pre>
<a href="#counting_iterator_traits">counting_iterator_traits</a>&lt;Incrementable&gt;::difference_type n;
i += n
n = i - j
i < j
</pre>
<h3>Members</h3>
The counting iterator type implements the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> concept. In addition it has the following
constructor:
<pre>
counting_iterator_generator::type(const Incrementable&amp; i)
</pre>
<p>
<hr>
<p>
<h2><a name="make_counting_iterator">The Counting Iterator Object Generator</a></h2>
<pre>
template &lt;class Incrementable&gt;
typename counting_iterator_generator&lt;Incrementable&gt;::type
make_counting_iterator(Incrementable base);
</pre>
An <a href="../../more/generic_programming.html#object_generator">object
generator</a> function that provides a convenient way to create counting
iterators.<p>
<h3>Example</h3>
In this example we count from negative five to positive five, this
time using the <tt>make_counting_iterator()</tt> function to save some
typing.
<pre>
// continuing from previous example...
std::cout &lt;&lt; "counting from -5 to 4:" &lt;&lt; std::endl;
std::copy(boost::make_counting_iterator(-5),
boost::make_counting_iterator(5),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
The output from this part is:
<pre>
counting from -5 to 4:
-5 -4 -3 -2 -1 0 1 2 3 4
</pre>
In the next example we create an array of numbers, and then create a
second array of pointers, where each pointer is the address of a
number in the first array. The counting iterator makes it easy to do
this since dereferencing a counting iterator that is wrapping an
iterator over the array of numbers just returns a pointer to the
current location in the array. We then use the <a
href="./indirect_iterator.htm">indirect iterator adaptor</a> to print
out the number in the array by accessing the numbers through the array
of pointers.
<pre>
// continuing from previous example...
const int N = 7;
std::vector&lt;int&gt; numbers;
// Fill "numbers" array with [0,N)
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
std::back_inserter(numbers));
std::vector&lt;std::vector&lt;int&gt;::iterator&gt; pointers;
// Use counting iterator to fill in the array of pointers.
std::copy(boost::make_counting_iterator(numbers.begin()),
boost::make_counting_iterator(numbers.end()),
std::back_inserter(pointers));
// Use indirect iterator to print out numbers by accessing
// them through the array of pointers.
std::cout &lt;&lt; "indirectly printing out the numbers from 0 to "
&lt;&lt; N &lt;&lt; std::endl;
std::copy(boost::make_indirect_iterator(pointers.begin()),
boost::make_indirect_iterator(pointers.end()),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
</pre>
The output is:
<pre>
indirectly printing out the numbers from 0 to 7
0 1 2 3 4 5 6
</pre>
<hr>
<h2><a name="counting_iterator_traits">Counting Iterator Traits</a></h2>
The counting iterator adaptor needs to determine the appropriate
<tt>difference_type</tt> and <tt>iterator_category</tt> to use based on the
<tt>Incrementable</tt> type supplied by the user. The
<tt>counting_iterator_traits</tt> class provides these types. If the
<tt>Incrementable</tt> type is an integral type or an iterator, these types
will be correctly deduced by the <tt>counting_iterator_traits</tt> provided by
the library. Otherwise, the user must specialize
<tt>counting_iterator_traits</tt> for her type or add nested typedefs to
her type to fulfill the needs of
<a href="http://www.sgi.com/tech/stl/iterator_traits.html">
<tt>std::iterator_traits</tt></a>.
<p>The following pseudocode describes how the <tt>counting_iterator_traits</tt> are determined:
<pre>
template &lt;class Incrementable&gt;
struct counting_iterator_traits
{
if (numeric_limits&lt;Incrementable&gt::is_specialized) {
if (!numeric_limits&lt;Incrementable&gt::is_integer)
COMPILE_TIME_ERROR;
if (!numeric_limits&lt;Incrementable&gt::is_bounded
&amp;&amp; numeric_limits&lt;Incrementable&gt;::is_signed) {
typedef Incrementable difference_type;
}
else if (numeric_limits&lt;Incrementable&gt::is_integral) {
typedef <i>next-larger-signed-type-or-intmax_t</i> difference_type;
}
typedef std::random_access_iterator_tag iterator_category;
} else {
typedef std::iterator_traits&lt;Incrementable&gt;::difference_type difference_type;
typedef std::iterator_traits&lt;Incrementable&gt;::iterator_category iterator_category;
}
};
</pre>
<p>The italicized sections above are implementation details, but it is important
to know that the <tt>difference_type</tt> for integral types is selected so that
it can always represent the difference between two values if such a built-in
integer exists. On platforms with a working <tt>std::numeric_limits</tt>
implementation, the <tt>difference_type</tt> for any variable-length signed
integer type <tt>T</tt> is <tt>T</tt> itself.
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>
<!-- LocalWords: html charset alt gif hpp incrementable const namespace htm
-->
<!-- LocalWords: struct typename iostream int Siek CopyConstructible pre
-->

View File

@@ -0,0 +1,53 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
#include <boost/config.hpp>
#include <iostream>
#include <iterator>
#include <vector>
#include <boost/counting_iterator.hpp>
#include <boost/iterator_adaptors.hpp>
int main(int, char*[])
{
// Example of using counting_iterator_generator
std::cout << "counting from 0 to 4:" << std::endl;
boost::counting_iterator_generator<int>::type first(0), last(4);
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Example of using make_counting_iterator()
std::cout << "counting from -5 to 4:" << std::endl;
std::copy(boost::make_counting_iterator(-5),
boost::make_counting_iterator(5),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Example of using counting iterator to create an array of pointers.
const int N = 7;
std::vector<int> numbers;
// Fill "numbers" array with [0,N)
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
std::back_inserter(numbers));
std::vector<std::vector<int>::iterator> pointers;
// Use counting iterator to fill in the array of pointers.
std::copy(boost::make_counting_iterator(numbers.begin()),
boost::make_counting_iterator(numbers.end()),
std::back_inserter(pointers));
// Use indirect iterator to print out numbers by accessing
// them through the array of pointers.
std::cout << "indirectly printing out the numbers from 0 to "
<< N << std::endl;
std::copy(boost::make_indirect_iterator(pointers.begin()),
boost::make_indirect_iterator(pointers.end()),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}

263
counting_iterator_test.cpp Normal file
View File

@@ -0,0 +1,263 @@
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears in
// all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// See http://www.boost.org for most recent version including documentation.
//
// Revision History
// 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with
// plain MSVC again. (David Abrahams)
// 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in
// MSVC without STLport, so that the other tests may proceed
// (David Abrahams)
// 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams)
// 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams)
// 24 Jan 2001 Initial revision (David Abrahams)
#include <boost/config.hpp>
#ifdef BOOST_MSVC
# pragma warning(disable:4786) // identifier truncated in debug info
#endif
#include <boost/pending/iterator_tests.hpp>
#include <boost/counting_iterator.hpp>
#include <boost/detail/iterator.hpp>
#include <iostream>
#include <climits>
#include <iterator>
#include <stdlib.h>
#include <boost/utility.hpp>
#include <vector>
#include <list>
#include <cassert>
#ifndef BOOST_NO_LIMITS
# include <limits>
#endif
#ifndef BOOST_NO_SLIST
# include <slist>
#endif
template <class T> struct is_numeric
{
enum { value =
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
std::numeric_limits<T>::is_specialized
#else
// Causes warnings with GCC, but how else can I detect numeric types at
// compile-time?
(boost::is_convertible<int,T>::value &&
boost::is_convertible<T,int>::value)
#endif
};
};
// Special tests for RandomAccess CountingIterators.
template <class CountingIterator>
void category_test(
CountingIterator start,
CountingIterator finish,
std::random_access_iterator_tag)
{
typedef typename
boost::detail::iterator_traits<CountingIterator>::difference_type
difference_type;
difference_type distance = boost::detail::distance(start, finish);
// Pick a random position internal to the range
difference_type offset = (unsigned)rand() % distance;
assert(offset >= 0);
CountingIterator internal = start;
std::advance(internal, offset);
// Try some binary searches on the range to show that it's ordered
assert(std::binary_search(start, finish, *internal));
CountingIterator x,y;
boost::tie(x,y) = std::equal_range(start, finish, *internal);
assert(boost::detail::distance(x, y) == 1);
// Show that values outside the range can't be found
assert(!std::binary_search(start, boost::prior(finish), *finish));
// Do the generic random_access_iterator_test
typedef typename CountingIterator::value_type value_type;
std::vector<value_type> v;
for (value_type z = *start; z != *finish; ++z)
v.push_back(z);
if (v.size() >= 2)
{
// Note that this test requires a that the first argument is
// dereferenceable /and/ a valid iterator prior to the first argument
boost::random_access_iterator_test(start + 1, v.size() - 1, v.begin() + 1);
}
}
// Special tests for bidirectional CountingIterators
template <class CountingIterator>
void category_test(CountingIterator start, CountingIterator finish, std::bidirectional_iterator_tag)
{
if (finish != start
&& finish != boost::next(start)
&& finish != boost::next(boost::next(start)))
{
// Note that this test requires a that the first argument is
// dereferenceable /and/ a valid iterator prior to the first argument
boost::bidirectional_iterator_test(boost::next(start), boost::next(*start), boost::next(boost::next(*start)));
}
}
template <class CountingIterator>
void category_test(CountingIterator start, CountingIterator finish, std::forward_iterator_tag)
{
if (finish != start && finish != boost::next(start))
boost::forward_iterator_test(start, *start, boost::next(*start));
}
template <class CountingIterator>
void test_aux(CountingIterator start, CountingIterator finish)
{
typedef typename CountingIterator::iterator_category category;
typedef typename CountingIterator::value_type value_type;
// If it's a RandomAccessIterator we can do a few delicate tests
category_test(start, finish, category());
// Okay, brute force...
for (CountingIterator p = start; p != finish && boost::next(p) != finish; ++p)
{
assert(boost::next(*p) == *boost::next(p));
}
// prove that a reference can be formed to these values
typedef typename CountingIterator::value_type value;
const value* q = &*start;
(void)q; // suppress unused variable warning
}
template <class Incrementable>
void test(Incrementable start, Incrementable finish)
{
test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish));
}
template <class Integer>
void test_integer(Integer* = 0) // default arg works around MSVC bug
{
Integer start = 0;
Integer finish = 120;
test(start, finish);
}
template <class Container>
void test_container(Container* = 0) // default arg works around MSVC bug
{
Container c(1 + (unsigned)rand() % 1673);
const typename Container::iterator start = c.begin();
// back off by 1 to leave room for dereferenceable value at the end
typename Container::iterator finish = start;
std::advance(finish, c.size() - 1);
test(start, finish);
typedef typename Container::const_iterator const_iterator;
test(const_iterator(start), const_iterator(finish));
}
class my_int1 {
public:
my_int1() { }
my_int1(int x) : m_int(x) { }
my_int1& operator++() { ++m_int; return *this; }
bool operator==(const my_int1& x) const { return m_int == x.m_int; }
private:
int m_int;
};
namespace boost {
template <>
struct counting_iterator_traits<my_int1> {
typedef std::ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
};
}
class my_int2 {
public:
typedef void value_type;
typedef void pointer;
typedef void reference;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
my_int2() { }
my_int2(int x) : m_int(x) { }
my_int2& operator++() { ++m_int; return *this; }
my_int2& operator--() { --m_int; return *this; }
bool operator==(const my_int2& x) const { return m_int == x.m_int; }
private:
int m_int;
};
class my_int3 {
public:
typedef void value_type;
typedef void pointer;
typedef void reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
my_int3() { }
my_int3(int x) : m_int(x) { }
my_int3& operator++() { ++m_int; return *this; }
my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; }
std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; }
my_int3& operator--() { --m_int; return *this; }
bool operator==(const my_int3& x) const { return m_int == x.m_int; }
bool operator!=(const my_int3& x) const { return m_int != x.m_int; }
bool operator<(const my_int3& x) const { return m_int < x.m_int; }
private:
int m_int;
};
int main()
{
// Test the built-in integer types.
test_integer<char>();
test_integer<unsigned char>();
test_integer<signed char>();
test_integer<wchar_t>();
test_integer<short>();
test_integer<unsigned short>();
test_integer<int>();
test_integer<unsigned int>();
test_integer<long>();
test_integer<unsigned long>();
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
test_integer<long long>();
test_integer<unsigned long long>();
#endif
// wrapping an iterator or non-built-in integer type causes an INTERNAL
// COMPILER ERROR in MSVC without STLport. I'm clueless as to why.
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
// Test user-defined type.
test_integer<my_int1>();
test_integer<my_int2>();
test_integer<my_int3>();
// Some tests on container iterators, to prove we handle a few different categories
test_container<std::vector<int> >();
test_container<std::list<int> >();
# ifndef BOOST_NO_SLIST
test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
# endif
// Also prove that we can handle raw pointers.
int array[2000];
test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1));
#endif
std::cout << "test successful " << std::endl;
return 0;
}

273
filter_iterator.htm Normal file
View File

@@ -0,0 +1,273 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Filter Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Filter Iterator Adaptor</h1>
Defined in header
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>
The filter iterator adaptor creates a view of an iterator range in
which some elements of the range are skipped over. A <a
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>
function object controls which elements are skipped. When the
predicate is applied to an element, if it returns <tt>true</tt> then
the element is retained and if it returns <tt>false</tt> then the
element is skipped over.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class Predicate, class BaseIterator, ...&gt;
class filter_iterator_generator;
template &lt;class Predicate, class BaseIterator&gt;
typename filter_iterator_generator&lt;Predicate, BaseIterator&gt;::type
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate());
}
</pre>
<hr>
<h2><a name="filter_iterator_generator">The Filter Iterator Type
Generator</a></h2>
The class <tt>filter_iterator_generator</tt> is a helper class whose
purpose is to construct a filter iterator type. The template
parameters for this class are the <tt>Predicate</tt> function object
type and the <tt>BaseIterator</tt> type that is being wrapped. In
most cases the associated types for the wrapped iterator can be
deduced from <tt>std::iterator_traits</tt>, but in some situations the
user may want to override these types, so there are also template
parameters for each of the iterator's associated types.
<pre>
template &lt;class Predicate, class BaseIterator,
class Value, class Reference, class Pointer, class Category, class Distance>
class filter_iterator_generator
{
public:
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt...&gt;</tt> type; // the resulting filter iterator type
}
</pre>
<h3>Example</h3>
The following example uses filter iterator to print out all the
positive integers in an array.
<pre>
struct is_positive_number {
bool operator()(int x) { return 0 &lt; x; }
};
int main() {
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
typedef boost::filter_iterator_generator&lt;is_positive_number, int*, int&gt;::type FilterIter;
is_positive_number predicate;
FilterIter::policies_type policies(predicate, numbers + N);
FilterIter filter_iter_first(numbers, policies);
FilterIter filter_iter_last(numbers + N, policies);
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
The output is:
<pre>
4 5 8
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><a href="http://www.sgi.com/tech/stl/Predicate.html"><tt>Predicate</tt></a></TD>
<TD>The function object that determines which elements are retained and which elements are skipped.
</TR>
<TR>
<TD><tt>BaseIterator</tt></TD>
<TD>The iterator type being wrapped. This type must at least be a model
of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD>
</TR>
<TR>
<TD><tt>Value</tt></TD>
<TD>The <tt>value_type</tt> of the resulting iterator,
unless const. If const, a conforming compiler strips constness for the
<tt>value_type</tt>. Typically the default for this parameter is the
appropriate type<a href="#1">[1]</a>.<br> <b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::value_type</TD>
</TR>
<TR>
<TD><tt>Reference</tt></TD>
<TD>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>. Typically the default for
this parameter is the appropriate type.<br> <b>Default:</b> If
<tt>Value</tt> is supplied, <tt>Value&amp;</tt> is used. Otherwise
<tt>std::iterator_traits&lt;BaseIterator&gt;::reference</tt> is
used.</TD>
</TR>
<TR>
<TD><tt>Pointer</tt></TD>
<TD>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator->()</tt>.
Typically the default for
this parameter is the appropriate type.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise <tt>std::iterator_traits&lt;BaseIterator&gt;::pointer</tt>.</TD>
</TR>
<TR>
<TD><tt>Category</tt></TD>
<TD>The <tt>iterator_category</tt> type for the resulting iterator.
Typically the
default for this parameter is the appropriate type. If you override
this parameter, do not use <tt>bidirectional_iterator_tag</tt>
because filter iterators can not go in reverse.<br>
<b>Default:</b> <tt>std::iterator_traits&lt;BaseIterator&gt;::iterator_category</tt></TD>
</TR>
<TR>
<TD><tt>Distance</tt></TD>
<TD>The <tt>difference_type</tt> for the resulting iterator. Typically the default for
this parameter is the appropriate type.<br>
<b>Default:</b> <tt>std::iterator_traits&lt;BaseIterator&gt;::difference_type</TD>
</TR>
</table>
<h3>Model of</h3>
The filter iterator adaptor (the type
<tt>filter_iterator_generator<...>::type</tt>) may be a model of <a
href="http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> or <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
depending on the adapted iterator type.
<h3>Members</h3>
The filter iterator type implements all of the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
concept. In addition it has the following constructor:
<pre>filter_iterator_generator::type(const BaseIterator& it, const Policies& p = Policies())</pre>
<p>
The policies type has only one public function, which is its constructor:
<pre>filter_iterator_generator::policies_type(const Predicate& p, const BaseIterator& end)</pre>
<p>
<hr>
<p>
<h2><a name="make_filter_iterator">The Make Filter Iterator Function</a></h2>
<pre>
template &lt;class Predicate, class BaseIterator&gt;
typename detail::filter_generator&lt;Predicate, BaseIterator&gt;::type
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate())
</pre>
This function provides a convenient way to create filter iterators.
<h3>Example</h3>
In this example we print out all numbers in the array that are
greater than negative two.
<pre>
int main()
{
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
std::copy(boost::make_filter_iterator(numbers, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
boost::make_filter_iterator(numbers + N, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
</pre>
The output is:
<pre>
0 -1 4 5 8
</pre>
<p>
In the next example we print the positive numbers using the
<tt>make_filter_iterator()</tt> function.
<pre>
struct is_positive_number {
bool operator()(int x) { return 0 &lt; x; }
};
int main()
{
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
std::copy(boost::make_filter_iterator&lt;is_positive_number&gt;(numbers, numbers + N),
boost::make_filter_iterator&lt;is_positive_number&gt;(numbers + N, numbers + N),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
The output is:
<pre>
4 5 8
</pre>
<h3>Notes</h3>
<a name="1">[1]</a> If the compiler does not support partial
specialization and the wrapped iterator type is a builtin pointer then
the <tt>Value</tt> type must be explicitly specified (don't use the
default).
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->09 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14894" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

View File

@@ -0,0 +1,53 @@
// Example of using the filter iterator adaptor from
// boost/iterator_adaptors.hpp.
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#include <boost/config.hpp>
#include <algorithm>
#include <functional>
#include <iostream>
#include <boost/iterator_adaptors.hpp>
struct is_positive_number {
bool operator()(int x) { return 0 < x; }
};
int main()
{
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
// Example using make_filter_iterator()
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Example using filter_iterator_generator
typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type
FilterIter;
is_positive_number predicate;
FilterIter::policies_type policies(predicate, numbers + N);
FilterIter filter_iter_first(numbers, policies);
FilterIter filter_iter_last(numbers + N, policies);
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
// Another example using make_filter_iterator()
std::copy(boost::make_filter_iterator(numbers, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
boost::make_filter_iterator(numbers + N, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}

41
fun_out_iter_example.cpp Normal file
View File

@@ -0,0 +1,41 @@
// (C) Copyright Jeremy Siek 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// Revision History:
// 27 Feb 2001 Jeremy Siek
// Initial checkin.
#include <iostream>
#include <string>
#include <vector>
#include <boost/function_output_iterator.hpp>
struct string_appender {
string_appender(std::string& s) : m_str(s) { }
void operator()(const std::string& x) const {
m_str += x;
}
std::string& m_str;
};
int main(int, char*[])
{
std::vector<std::string> x;
x.push_back("hello");
x.push_back(" ");
x.push_back("world");
x.push_back("!");
std::string s = "";
std::copy(x.begin(), x.end(),
boost::make_function_output_iterator(string_appender(s)));
std::cout << s << std::endl;
return 0;
}

View File

@@ -0,0 +1,169 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Function Output Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"center" width="277" height="86">
<h1>Function Output Iterator Adaptor</h1>
Defined in header <a href=
"../../boost/function_output_iterator.hpp">boost/function_output_iterator.hpp</a>
<p>The function output iterator adaptor makes it easier to create
custom output iterators. The adaptor takes a <a
href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
Function</a> and creates a model of <a
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
Iterator</a>. Each item assigned to the output iterator is passed
as an argument to the unary function. The motivation for this
iterator is that creating a C++ Standard conforming output
iterator is non-trivial, particularly because the proper
implementation usually requires a proxy object. On the other hand,
creating a function (or function object) is much simpler.
<h2>Synopsis</h2>
<blockquote>
<pre>
namespace boost {
template &lt;class UnaryFunction&gt;
class function_output_iterator;
template &lt;class UnaryFunction&gt;
function_output_iterator&lt;UnaryFunction&gt;
make_function_output_iterator(const UnaryFunction&amp; f = UnaryFunction())
}
</pre>
</blockquote>
<h3>Example</h3>
In this example we create an output iterator that appends
each item onto the end of a string, using the <tt>string_appender</tt>
function.
<blockquote>
<pre>
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;boost/function_output_iterator.hpp&gt;
struct string_appender {
string_appender(std::string&amp; s) : m_str(s) { }
void operator()(const std::string&amp; x) const {
m_str += x;
}
std::string&amp; m_str;
};
int main(int, char*[])
{
std::vector&lt;std::string&gt; x;
x.push_back("hello");
x.push_back(" ");
x.push_back("world");
x.push_back("!");
std::string s = "";
std::copy(x.begin(), x.end(),
boost::make_function_output_iterator(string_appender(s)));
std::cout &lt;&lt; s &lt;&lt; std::endl;
return 0;
}
</pre>
</blockquote>
<hr>
<h2><a name="function_output_iterator">The Function Output Iterator Class</a></h2>
<blockquote>
<pre>
template &lt;class UnaryFunction&gt;
class function_output_iterator;
</pre>
</blockquote>
The <tt>function_output_iterator</tt> class creates an <a
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
Iterator</a> out of a
<a href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
Function</a>. Each item assigned to the output iterator is passed
as an argument to the unary function.
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt>UnaryFunction</tt>
<td>The function type being wrapped. The return type of the
function is not used, so it can be <tt>void</tt>. The
function must be a model of <a
href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary
Function</a>.</td>
</table>
<h3>Concept Model</h3>
The function output iterator class is a model of <a
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
Iterator</a>.
<h2>Members</h3>
The function output iterator implements the member functions
and operators required of the <a
href="http://www.sgi.com/tech/stl/OutputIterator.html">Output
Iterator</a> concept. In addition it has the following constructor:
<pre>
explicit function_output_iterator(const UnaryFunction& f = UnaryFunction())
</pre>
<br>
<br>
<hr>
<h2><a name="make_function_output_iterator">The Function Output Iterator Object
Generator</a></h2>
The <tt>make_function_output_iterator()</tt> function provides a
more convenient way to create function output iterator objects. The
function saves the user the trouble of explicitly writing out the
iterator types. If the default argument is used, the function
type must be provided as an explicit template argument.
<blockquote>
<pre>
template &lt;class UnaryFunction&gt;
function_output_iterator&lt;UnaryFunction&gt;
make_function_output_iterator(const UnaryFunction&amp; f = UnaryFunction())
</pre>
</blockquote>
<hr>
<p>&copy; Copyright Jeremy Siek 2001. Permission to copy, use,
modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided
"as is" without express or implied warranty, and with no claim as
to its suitability for any purpose.
</body>
</html>

View File

@@ -1,565 +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
// 11 Feb 01 Fixed bugs in the iterator helpers which prevented explicitly
// supplied arguments from actually being used (Dave Abrahams)
// 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,P,R
> > > > {};
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,P,R
> > > > > {};
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,P,R
> > > > > > > > >
{
#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

443
indirect_iterator.htm Normal file
View File

@@ -0,0 +1,443 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Indirect Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"center" width="277" height="86">
<h1>Indirect Iterator Adaptor</h1>
Defined in header <a href=
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>The indirect iterator adaptor augments an iterator by applying an
<b>extra</b> dereference inside of <tt>operator*()</tt>. For example, this
iterator makes it possible to view a container of pointers or
smart-pointers (e.g. <tt>std::list&lt;boost::shared_ptr&lt;foo&gt;
&gt;</tt>) as if it were a container of the pointed-to type. The following
<b>pseudo-code</b> shows the basic idea of the indirect iterator:
<blockquote>
<pre>
// inside a hypothetical indirect_iterator class...
typedef std::iterator_traits&lt;BaseIterator&gt;::value_type Pointer;
typedef std::iterator_traits&lt;Pointer&gt;::reference reference;
reference indirect_iterator::operator*() const {
return **this-&gt;base_iterator;
}
</pre>
</blockquote>
<h2>Synopsis</h2>
<blockquote>
<pre>
namespace boost {
template &lt;class BaseIterator,
class Value, class Reference, class Category, class Pointer&gt;
struct indirect_iterator_generator;
template &lt;class BaseIterator,
class Value, class Reference, class ConstReference,
class Category, class Pointer, class ConstPointer&gt;
struct indirect_iterator_pair_generator;
template &lt;class BaseIterator&gt;
typename indirect_iterator_generator&lt;BaseIterator&gt;::type
make_indirect_iterator(BaseIterator base)
}
</pre>
</blockquote>
<hr>
<h2><a name="indirect_iterator_generator">The Indirect Iterator Type
Generator</a></h2>
The <tt>indirect_iterator_generator</tt> template is a <a href=
"../../more/generic_programming.html#type_generator">generator</a> of
indirect iterator types. The main template parameter for this class is the
<tt>BaseIterator</tt> type that is being wrapped. In most cases the type of
the elements being pointed to can be deduced using
<tt>std::iterator_traits</tt>, but in some situations the user may want to
override this type, so there are also template parameters that allow a user
to control the <tt>value_type</tt>, <tt>pointer</tt>, and
<tt>reference</tt> types of the resulting iterators.
<blockquote>
<pre>
template &lt;class BaseIterator,
class Value, class Reference, class Pointer&gt;
class indirect_iterator_generator
{
public:
typedef <tt><a href=
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt;</tt> type; // the resulting indirect iterator type
};
</pre>
</blockquote>
<h3>Example</h3>
This example uses the <tt>indirect_iterator_generator</tt> to create
indirect iterators which dereference the pointers stored in the
<tt>pointers_to_chars</tt> array to access the <tt>char</tt>s in the
<tt>characters</tt> array.
<blockquote>
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;iterator&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
int main(int, char*[])
{
char characters[] = "abcdefg";
const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char
char* pointers_to_chars[N]; // at the end.
for (int i = 0; i &lt; N; ++i)
pointers_to_chars[i] = &amp;characters[i];
boost::indirect_iterator_generator&lt;char**, char&gt;::type
indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N);
std::copy(indirect_first, indirect_last, std::ostream_iterator&lt;char&gt;(std::cout, ","));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
</blockquote>
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt>BaseIterator</tt>
<td>The iterator type being wrapped. The <tt>value_type</tt>
of the base iterator should itself be dereferenceable.
The return type of the <tt>operator*</tt> for the
<tt>value_type</tt> should match the <tt>Reference</tt> type.
<tr>
<td><tt>Value</tt>
<td>The <tt>value_type</tt> of the resulting iterator, unless const. If
Value is <tt>const X</tt>, a conforming compiler makes the
<tt>value_type</tt> <tt><i>non-</i>const X</tt><a href=
"iterator_adaptors.htm#1">[1]</a>. Note that if the default
is used for <tt>Value</tt>, then there must be a valid specialization
of <tt>iterator_traits</tt> for the value type of the base iterator.
<br>
<b>Default:</b> <tt>std::iterator_traits&lt;<br>
<20> std::iterator_traits&lt;BaseIterator&gt;::value_type
&gt;::value_type</tt><a href="#2">[2]</a>
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>.<br>
<b>Default:</b> <tt>Value&amp;</tt>
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> <tt>Value*</tt>
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::iterator_category</tt>
</table>
<h3>Concept Model</h3>
The indirect iterator will model whichever <a href=
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator
concept category</a> is modeled by the base iterator. Thus, if the
base iterator is a model of <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> then so is the resulting indirect iterator. If
the base iterator models a more restrictive concept, the resulting
indirect iterator will model the same concept <a href="#3">[3]</a>.
<h3>Members</h3>
The indirect iterator type implements the member functions and operators
required of the <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> concept. In addition it has the following constructor:
<pre>
explicit indirect_iterator_generator::type(const BaseIterator&amp; it)
</pre>
<br>
<br>
<hr>
<p>
<h2><a name="indirect_iterator_pair_generator">The Indirect Iterator Pair
Generator</a></h2>
Sometimes a pair of <tt>const</tt>/non-<tt>const</tt> pair of iterators is
needed, such as when implementing a container. The
<tt>indirect_iterator_pair_generator</tt> class makes it more convenient to
create this pair of iterator types.
<blockquote>
<pre>
template &lt;class BaseIterator,
class Value, class Pointer, class Reference,
class ConstPointer, class ConstReference&gt;
class indirect_iterator_pair_generator
{
public:
typedef <tt><a href=
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt;</tt> iterator; // the mutable indirect iterator type
typedef <tt><a href=
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt;</tt> const_iterator; // the immutable indirect iterator type
};
</pre>
</blockquote>
<h3>Example</h3>
<blockquote>
<pre>
// continuing from the last example...
typedef boost::indirect_iterator_pair_generator&lt;char**,
char, char*, char&amp;, const char*, const char&amp;&gt; PairGen;
char mutable_characters[N];
char* pointers_to_mutable_chars[N];
for (int i = 0; i &lt; N; ++i)
pointers_to_mutable_chars[i] = &amp;mutable_characters[i];
PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars),
mutable_indirect_last(pointers_to_mutable_chars + N);
PairGen::const_iterator const_indirect_first(pointers_to_chars),
const_indirect_last(pointers_to_chars + N);
std::transform(const_indirect_first, const_indirect_last,
mutable_indirect_first, std::bind1st(std::plus&lt;char&gt;(), 1));
std::copy(mutable_indirect_first, mutable_indirect_last,
std::ostream_iterator&lt;char&gt;(std::cout, ","));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
</blockquote>
<p>The output is:
<blockquote>
<pre>
b,c,d,e,f,g,h,
</pre>
</blockquote>
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt>BaseIterator</tt>
<td>The iterator type being wrapped. The <tt>value_type</tt> of the
base iterator should itself be dereferenceable.
The return type of the <tt>operator*</tt> for the
<tt>value_type</tt> should match the <tt>Reference</tt> type.
<tr>
<td><tt>Value</tt>
<td>The <tt>value_type</tt> of the resulting iterators.
If Value is <tt>const X</tt>, a conforming compiler makes the
<tt>value_type</tt> <tt><i>non-</i>const X</tt><a href=
"iterator_adaptors.htm#1">[1]</a>. Note that if the default
is used for <tt>Value</tt>, then there must be a valid
specialization of <tt>iterator_traits</tt> for the value type
of the base iterator.<br>
<b>Default:</b> <tt>std::iterator_traits&lt;<br>
<20> std::iterator_traits&lt;BaseIterator&gt;::value_type
&gt;::value_type</tt><a href="#2">[2]</a>
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting <tt>iterator</tt>, and
in particular, the result type of its <tt>operator*()</tt>.<br>
<b>Default:</b> <tt>Value&amp;</tt>
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting <tt>iterator</tt>, and
in particular, the result type of its <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> <tt>Value*</tt>
<tr>
<td><tt>ConstReference</tt>
<td>The <tt>reference</tt> type of the resulting
<tt>const_iterator</tt>, and in particular, the result type of its
<tt>operator*()</tt>.<br>
<b>Default:</b> <tt>const Value&amp;</tt>
<tr>
<td><tt>ConstPointer</tt>
<td>The <tt>pointer</tt> type of the resulting <tt>const_iterator</tt>,
and in particular, the result type of its <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> <tt>const Value*</tt>
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::iterator_category</tt>
</table>
<h3>Concept Model</h3>
The indirect iterators will model whichever <a href=
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator
concept category</a> is modeled by the base iterator. Thus, if the
base iterator is a model of <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> then so are the resulting indirect
iterators. If the base iterator models a more restrictive concept,
the resulting indirect iterators will model the same concept <a
href="#3">[3]</a>.
<h3>Members</h3>
The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types implement
the member functions and operators required of the <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> concept. In addition they support the following constructors:
<blockquote>
<pre>
explicit indirect_iterator_pair_generator::iterator(const BaseIterator&amp; it)
explicit indirect_iterator_pair_generator::const_iterator(const BaseIterator&amp; it)
</pre>
</blockquote>
<br>
<br>
<hr>
<p>
<h2><a name="make_indirect_iterator">The Indirect Iterator Object
Generator</a></h2>
The <tt>make_indirect_iterator()</tt> function provides a more convenient
way to create indirect iterator objects. The function saves the user the
trouble of explicitly writing out the iterator types.
<blockquote>
<pre>
template &lt;class BaseIterator&gt;
typename indirect_iterator_generator&lt;BaseIterator&gt;::type
make_indirect_iterator(BaseIterator base)
</pre>
</blockquote>
<h3>Example</h3>
Here we again print the <tt>char</tt>s from the array <tt>characters</tt>
by accessing them through the array of pointers <tt>pointer_to_chars</tt>,
but this time we use the <tt>make_indirect_iterator()</tt> function which
saves us some typing.
<blockquote>
<pre>
// continuing from the last example...
std::copy(boost::make_indirect_iterator(pointers_to_chars),
boost::make_indirect_iterator(pointers_to_chars + N),
std::ostream_iterator&lt;char&gt;(std::cout, ","));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
</blockquote>
The output is:
<blockquote>
<pre>
a,b,c,d,e,f,g,
</pre>
</blockquote>
<hr>
<h3>Notes</h3>
<p>
<p><a name="2">[2]</a> If your compiler does not support partial
specialization and the base iterator or its <tt>value_type</tt> is a
builtin pointer type, you will not be able to use the default for
<tt>Value</tt> and will need to specify this type explicitly.
<p><a name="3">[3]</a>There is a caveat to which concept the
indirect iterator can model. If the return type of the
<tt>operator*</tt> for the base iterator's value type is not a
true reference, then strickly speaking, the indirect iterator can
not be a model of <a href=
"http://www.sgi.com/tech/stl/ForwardIterator.html">Forward
Iterator</a> or any of the concepts that refine it. In this case
the <tt>Category</tt> for the indirect iterator should be
specified as <tt>std::input_iterator_tag</tt>. However, even in
this case, if the base iterator is a random access iterator, the
resulting indirect iterator will still satisfy most of the
requirements for <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a>.
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
<p>&copy; Copyright Jeremy Siek and David Abrahams 2001. Permission to
copy, use, modify, sell and distribute this document is granted provided
this copyright notice appears in all copies. This document is provided "as
is" without express or implied warranty, and with no claim as to its
suitability for any purpose.
<!-- LocalWords: html charset alt gif hpp BaseIterator const namespace struct
-->
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
-->
<!-- LocalWords: sizeof PairGen pre Jeremy Siek David Abrahams
-->
</body>
</html>

View File

@@ -29,8 +29,7 @@ int main(int, char*[])
// Example of using indirect_iterator_pair_generator
typedef boost::indirect_iterator_pair_generator<char**,
char, char*, char&, const char*, const char&> PairGen;
typedef boost::indirect_iterator_pair_generator<char**, char> PairGen;
char mutable_characters[N];
char* pointers_to_mutable_chars[N];

151
indirect_iterator_test.cpp Normal file
View File

@@ -0,0 +1,151 @@
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// Revision History
// 08 Mar 2001 Jeremy Siek
// Moved test of indirect iterator into its own file. It to
// to be in iterator_adaptor_test.cpp.
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/iterator_adaptors.hpp>
#include <boost/pending/iterator_tests.hpp>
#include <boost/concept_archetype.hpp>
#include <stdlib.h>
#include <deque>
#include <set>
struct my_iterator_tag : public std::random_access_iterator_tag { };
using boost::dummyT;
typedef std::deque<int> storage;
typedef std::deque<int*> pointer_deque;
typedef std::set<storage::iterator> iterator_set;
void more_indirect_iterator_tests()
{
// For some reason all heck breaks loose in the compiler under these conditions.
#if !defined(BOOST_MSVC) || !defined(__STL_DEBUG)
storage store(1000);
std::generate(store.begin(), store.end(), rand);
pointer_deque ptr_deque;
iterator_set iter_set;
for (storage::iterator p = store.begin(); p != store.end(); ++p)
{
ptr_deque.push_back(&*p);
iter_set.insert(p);
}
typedef boost::indirect_iterator_pair_generator<
pointer_deque::iterator
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, int
#endif
> IndirectDeque;
IndirectDeque::iterator db(ptr_deque.begin());
IndirectDeque::iterator de(ptr_deque.end());
assert(static_cast<std::size_t>(de - db) == store.size());
assert(db + store.size() == de);
IndirectDeque::const_iterator dci(db);
assert(db == dci);
assert(dci == db);
assert(dci != de);
assert(dci < de);
assert(dci <= de);
assert(de >= dci);
assert(de > dci);
dci = de;
assert(dci == de);
boost::random_access_iterator_test(db + 1, store.size() - 1, boost::next(store.begin()));
*db = 999;
assert(store.front() == 999);
// Borland C++ is getting very confused about the typedef's here
typedef boost::indirect_iterator_generator<
iterator_set::iterator
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, int
#endif
>::type indirect_set_iterator;
typedef boost::indirect_iterator_generator<
iterator_set::iterator,
const int
>::type const_indirect_set_iterator;
indirect_set_iterator sb(iter_set.begin());
indirect_set_iterator se(iter_set.end());
const_indirect_set_iterator sci(iter_set.begin());
assert(sci == sb);
assert(sci != se);
sci = se;
assert(sci == se);
*boost::prior(se) = 888;
assert(store.back() == 888);
assert(std::equal(sb, se, store.begin()));
boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]);
assert(std::equal(db, de, store.begin()));
#endif
}
int
main()
{
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
dummyT(3), dummyT(4), dummyT(5) };
const int N = sizeof(array)/sizeof(dummyT);
// Test indirect_iterator_generator
{
dummyT* ptr[N];
for (int k = 0; k < N; ++k)
ptr[k] = array + k;
typedef boost::indirect_iterator_generator<dummyT**
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
>::type indirect_iterator;
typedef boost::indirect_iterator_generator<dummyT**, const dummyT>::type const_indirect_iterator;
indirect_iterator i(ptr);
boost::random_access_iterator_test(i, N, array);
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);
#endif
// check operator->
assert((*i).m_x == i->foo());
const_indirect_iterator j(ptr);
boost::random_access_iterator_test(j, N, array);
dummyT*const* const_ptr = ptr;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array);
#endif
boost::const_nonconst_iterator_test(i, ++j);
more_indirect_iterator_tests();
}
std::cout << "test successful " << std::endl;
return 0;
}

View File

@@ -0,0 +1,27 @@
// Test boost/pending/iterator_adaptors.hpp
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 21 Jan 01 Initial version (Jeremy Siek)
#include <boost/config.hpp>
#include <list>
#include <boost/pending/iterator_adaptors.hpp>
int main()
{
typedef boost::iterator_adaptor<std::list<int>::iterator,
boost::default_iterator_policies,
int,int&,int*,std::bidirectional_iterator_tag> adaptor_type;
adaptor_type i;
i += 4;
return 0;
}

View File

@@ -0,0 +1,28 @@
// Test boost/pending/iterator_adaptors.hpp
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 21 Jan 01 Initial version (Jeremy Siek)
#include <boost/config.hpp>
#include <iostream>
#include <iterator>
#include <boost/pending/iterator_adaptors.hpp>
int main()
{
typedef boost::iterator_adaptor<std::istream_iterator<int>,
boost::default_iterator_policies,
int,int&,int*,std::input_iterator_tag> adaptor_type;
adaptor_type iter;
--iter;
return 0;
}

61
iter_traits_gen_test.cpp Normal file
View File

@@ -0,0 +1,61 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// 8 Mar 2001 Jeremy Siek
// Initial checkin.
#include <boost/iterator_adaptors.hpp>
#include <boost/pending/iterator_tests.hpp>
#include <boost/static_assert.hpp>
class bar { };
void foo(bar) { }
int
main()
{
using boost::dummyT;
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
dummyT(3), dummyT(4), dummyT(5) };
typedef boost::iterator_adaptor<dummyT*,
boost::default_iterator_policies, dummyT> my_iter;
my_iter mi(array);
{
typedef boost::iterator_adaptor<my_iter, boost::default_iterator_policies,
boost::iterator_traits_generator
::reference<dummyT>
::iterator_category<std::input_iterator_tag> > iter_type;
BOOST_STATIC_ASSERT((boost::is_same<iter_type::iterator_category*,
std::input_iterator_tag*>::value));
BOOST_STATIC_ASSERT(( ! boost::is_convertible<iter_type::iterator_category*,
std::forward_iterator_tag*>::value));
iter_type i(mi);
boost::input_iterator_test(i, dummyT(0), dummyT(1));
}
{
typedef boost::iterator_adaptor<dummyT*,
boost::default_iterator_policies,
boost::iterator_traits_generator
::value_type<dummyT>
::reference<const dummyT&>
::pointer<const dummyT*>
::iterator_category<std::forward_iterator_tag>
::difference_type<std::ptrdiff_t> > adaptor_type;
adaptor_type i(array);
boost::input_iterator_test(i, dummyT(0), dummyT(1));
int zero = 0;
if (zero) // don't do this, just make sure it compiles
assert((*i).m_x == i->foo());
}
return 0;
}

View File

@@ -0,0 +1,47 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
#include <functional>
#include <algorithm>
#include <iostream>
#include <boost/pending/iterator_adaptors.hpp>
#include <boost/pending/integer_range.hpp>
int
main(int, char*[])
{
// This is a simple example of using the transform_iterators class to
// generate iterators that multiply the value returned by dereferencing
// the iterator. In this case we are multiplying by 2.
// Would be cooler to use lambda library in this example.
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
typedef std::binder1st< std::multiplies<int> > Function;
typedef boost::transform_iterator<Function, int*,
boost::iterator<std::random_access_iterator_tag, int>
>::type doubling_iterator;
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
std::cout << "multiplying the array by 2:" << std::endl;
while (i != i_end)
std::cout << *i++ << " ";
std::cout << std::endl;
// Here is an example of counting from 0 to 5 using the integer_range class.
boost::integer_range<int> r(0,5);
std::cout << "counting to from 0 to 4:" << std::endl;
std::copy(r.begin(), r.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}

335
iterator_adaptor_test.cpp Normal file
View File

@@ -0,0 +1,335 @@
// Test boost/iterator_adaptors.hpp
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 08 Mar 01 Moved indirect and transform tests to separate files.
// (Jeremy Siek)
// 19 Feb 01 Take adavantage of improved iterator_traits to do more tests
// on MSVC. Hack around an MSVC-with-STLport internal compiler
// error. (David Abrahams)
// 11 Feb 01 Added test of operator-> for forward and input iterators.
// (Jeremy Siek)
// 11 Feb 01 Borland fixes (David Abrahams)
// 10 Feb 01 Use new adaptors interface. (David Abrahams)
// 10 Feb 01 Use new filter_ interface. (David Abrahams)
// 09 Feb 01 Use new reverse_ and indirect_ interfaces. Replace
// BOOST_NO_STD_ITERATOR_TRAITS with
// BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've
// normalized to core compiler capabilities (David Abrahams)
// 08 Feb 01 Use Jeremy's new make_reverse_iterator form; add more
// comprehensive testing. Force-decay array function arguments to
// pointers.
// 07 Feb 01 Added tests for the make_xxx_iterator() helper functions.
// (Jeremy Siek)
// 07 Feb 01 Replaced use of xxx_pair_generator with xxx_generator where
// possible (which was all but the projection iterator).
// (Jeremy Siek)
// 06 Feb 01 Removed now-defaulted template arguments where possible
// Updated names to correspond to new generator naming convention.
// Added a trivial test for make_transform_iterator().
// Gave traits for const iterators a mutable value_type, per std.
// Resurrected my original tests for indirect iterators.
// (David Abrahams)
// 04 Feb 01 Fix for compilers without standard iterator_traits
// (David Abrahams)
// 13 Jun 00 Added const version of the iterator tests (Jeremy Siek)
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <functional>
#include <boost/iterator_adaptors.hpp>
#include <boost/pending/iterator_tests.hpp>
#include <boost/pending/integer_range.hpp>
#include <boost/concept_archetype.hpp>
#include <stdlib.h>
#include <vector>
#include <deque>
#include <set>
struct my_iterator_tag : public std::random_access_iterator_tag { };
using boost::dummyT;
struct mult_functor {
typedef int result_type;
typedef int argument_type;
// Functors used with transform_iterator must be
// DefaultConstructible, as the transform_iterator must be
// DefaultConstructible to satisfy the requirements for
// TrivialIterator.
mult_functor() { }
mult_functor(int aa) : a(aa) { }
int operator()(int b) const { return a * b; }
int a;
};
template <class Pair>
struct select1st_
: public std::unary_function<Pair, typename Pair::first_type>
{
const typename Pair::first_type& operator()(const Pair& x) const {
return x.first;
}
typename Pair::first_type& operator()(Pair& x) const {
return x.first;
}
};
struct one_or_four {
bool operator()(dummyT x) const {
return x.foo() == 1 || x.foo() == 4;
}
};
typedef std::deque<int> storage;
typedef std::deque<int*> pointer_deque;
typedef std::set<storage::iterator> iterator_set;
int
main()
{
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
dummyT(3), dummyT(4), dummyT(5) };
const int N = sizeof(array)/sizeof(dummyT);
// sanity check, if this doesn't pass the test is buggy
boost::random_access_iterator_test(array,N,array);
// Check that the policy concept checks and the default policy
// implementation match up.
boost::function_requires<
boost::RandomAccessIteratorPoliciesConcept<
boost::default_iterator_policies, int*,
boost::iterator<std::random_access_iterator_tag, int, std::ptrdiff_t,
int*, int&>
> >();
// Test the iterator_adaptor
{
boost::iterator_adaptor<dummyT*, boost::default_iterator_policies, dummyT> i(array);
boost::random_access_iterator_test(i, N, array);
boost::iterator_adaptor<const dummyT*, boost::default_iterator_policies, const dummyT> j(array);
boost::random_access_iterator_test(j, N, array);
boost::const_nonconst_iterator_test(i, ++j);
}
// Test projection_iterator_pair_generator
{
typedef std::pair<dummyT,dummyT> Pair;
Pair pair_array[N];
for (int k = 0; k < N; ++k)
pair_array[k].first = array[k];
typedef boost::projection_iterator_pair_generator<select1st_<Pair>,
Pair*, const Pair*
> Projection;
Projection::iterator i(pair_array);
boost::random_access_iterator_test(i, N, array);
boost::random_access_iterator_test(boost::make_projection_iterator(pair_array, select1st_<Pair>()), N, array);
boost::random_access_iterator_test(boost::make_projection_iterator< select1st_<Pair> >(pair_array), N, array);
Projection::const_iterator j(pair_array);
boost::random_access_iterator_test(j, N, array);
boost::random_access_iterator_test(boost::make_const_projection_iterator(pair_array, select1st_<Pair>()), N, array);
boost::random_access_iterator_test(boost::make_const_projection_iterator<select1st_<Pair> >(pair_array), N, array);
boost::const_nonconst_iterator_test(i, ++j);
}
// Test reverse_iterator_generator
{
dummyT reversed[N];
std::copy(array, array + N, reversed);
std::reverse(reversed, reversed + N);
typedef boost::reverse_iterator_generator<dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
>::type reverse_iterator;
reverse_iterator i(reversed + N);
boost::random_access_iterator_test(i, N, array);
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
#endif
typedef boost::reverse_iterator_generator<const dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, const dummyT
#endif
>::type const_reverse_iterator;
const_reverse_iterator j(reversed + N);
boost::random_access_iterator_test(j, N, array);
const dummyT* const_reversed = reversed;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
#endif
boost::const_nonconst_iterator_test(i, ++j);
}
// Test reverse_iterator_generator again, with traits fully deducible on all platforms
{
std::deque<dummyT> reversed_container;
std::reverse_copy(array, array + N, std::back_inserter(reversed_container));
const std::deque<dummyT>::iterator reversed = reversed_container.begin();
typedef boost::reverse_iterator_generator<
std::deque<dummyT>::iterator>::type reverse_iterator;
typedef boost::reverse_iterator_generator<
std::deque<dummyT>::const_iterator, const dummyT>::type const_reverse_iterator;
// MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation
// (e.g. "reversed + N") is used in the constructor below.
const std::deque<dummyT>::iterator finish = reversed_container.end();
reverse_iterator i(finish);
boost::random_access_iterator_test(i, N, array);
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
const_reverse_iterator j = reverse_iterator(finish);
boost::random_access_iterator_test(j, N, array);
const std::deque<dummyT>::const_iterator const_reversed = reversed;
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
// Many compilers' builtin deque iterators don't interoperate well, though
// STLport fixes that problem.
#if defined(__SGI_STL_PORT) || !defined(__GNUC__) && !defined(__BORLANDC__) && !defined(BOOST_MSVC)
boost::const_nonconst_iterator_test(i, ++j);
#endif
}
// Test integer_range's iterators
{
int int_array[] = { 0, 1, 2, 3, 4, 5 };
boost::integer_range<int> r(0, 5);
boost::random_access_iterator_test(r.begin(), r.size(), int_array);
}
// Test filter iterator
{
// Using typedefs for filter_gen::type confused Borland terribly.
typedef boost::detail::non_bidirectional_category<dummyT*>::type category;
typedef boost::filter_iterator_generator<one_or_four, dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
>::type filter_iter;
#if defined(__BORLANDC__)
// Borland is choking on accessing the policies_type explicitly
// from the filter_iter.
boost::forward_iterator_test(make_filter_iterator(array, array+N,
one_or_four()),
dummyT(1), dummyT(4));
#else
filter_iter i(array, filter_iter::policies_type(one_or_four(), array + N));
boost::forward_iterator_test(i, dummyT(1), dummyT(4));
#endif
#if !defined(__BORLANDC__)
//
enum { is_forward = boost::is_same<
filter_iter::iterator_category,
std::forward_iterator_tag>::value };
BOOST_STATIC_ASSERT(is_forward);
#endif
// On compilers not supporting partial specialization, we can do more type
// deduction with deque iterators than with pointers... unless the library
// is broken ;-(
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
std::deque<dummyT> array2;
std::copy(array+0, array+N, std::back_inserter(array2));
boost::forward_iterator_test(
boost::make_filter_iterator(array2.begin(), array2.end(), one_or_four()),
dummyT(1), dummyT(4));
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()),
dummyT(1), dummyT(4));
#endif
#if !defined(BOOST_MSVC) // This just freaks MSVC out completely
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(
boost::make_reverse_iterator(array2.end()),
boost::make_reverse_iterator(array2.begin())
),
dummyT(4), dummyT(1));
#endif
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::forward_iterator_test(
boost::make_filter_iterator(array+0, array+N, one_or_four()),
dummyT(1), dummyT(4));
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(array, array + N),
dummyT(1), dummyT(4));
#endif
}
// check operator-> with a forward iterator
{
boost::forward_iterator_archetype<dummyT> forward_iter;
#if defined(__BORLANDC__)
typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
boost::default_iterator_policies,
dummyT, const dummyT&, const dummyT*,
std::forward_iterator_tag, std::ptrdiff_t> adaptor_type;
#else
typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
boost::default_iterator_policies,
boost::iterator_traits_generator
::value_type<dummyT>
::reference<const dummyT&>
::pointer<const dummyT*>
::iterator_category<std::forward_iterator_tag>
::difference_type<std::ptrdiff_t> > adaptor_type;
#endif
adaptor_type i(forward_iter);
int zero = 0;
if (zero) // don't do this, just make sure it compiles
assert((*i).m_x == i->foo());
}
// check operator-> with an input iterator
{
boost::input_iterator_archetype<dummyT> input_iter;
typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>,
boost::default_iterator_policies,
dummyT, const dummyT&, const dummyT*,
std::input_iterator_tag, std::ptrdiff_t> adaptor_type;
adaptor_type i(input_iter);
int zero = 0;
if (zero) // don't do this, just make sure it compiles
assert((*i).m_x == i->foo());
}
std::cout << "test successful " << std::endl;
return 0;
}

891
iterator_adaptors.htm Normal file
View File

@@ -0,0 +1,891 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Boost Iterator Adaptor Library</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>Boost Iterator Adaptor Library</h1>
<h2>Introduction</h2>
<p>The Iterator Adaptor library allows you transform an arbitrary ``base''
type into a standard-conforming iterator with the behaviors you choose.
Doing so is especially easy if the ``base'' type is itself an iterator. The
library also supplies several example <a href=
"../../more/generic_programming.html#adaptors">adaptors</a> which apply
specific useful behaviors to arbitrary base iterators.
<h2>Table of Contents</h2>
<ul>
<li>
Header <tt><a href=
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a></tt>
<ul>
<li>
Generalized Iterator Adaptor
<ul>
<li>Class template <tt><a href=
"#iterator_adaptor">iterator_adaptor</a></tt>
<li><a href="#template_parameters">Template Parameters</a>
<li><a href="#named_template_parameters">Named Template Parameters</a>
<li><a href="#policies">The Policies Class</a>
<li><a href="#additional_members">Additional Class Members</a>
<li><a href="#example">Example</a>
<li>(<tt>const</tt>/non-<tt>const</tt>) <a href=
"#iterator_interactions">Iterator Interactions</a>
<li><a href="#challenge">Challenge</a>
<li><a href="#concept_model">Concept Model</a>
<li><a href="#declaration_synopsis">Declaration Synopsis</a>
<li><a href="#notes">Notes</a>
</ul>
<li>
<a name="specialized_adaptors">Specialized Iterator Adaptors</a>
<ul>
<li><a href="indirect_iterator.htm">Indirect Iterator Adaptor</a>
<li><a href="reverse_iterator.htm">Reverse Iterator Adaptor</a>
<li><a href="transform_iterator.htm">Transform Iterator
Adaptor</a>
<li><a href="projection_iterator.htm">Projection Iterator
Adaptor</a>
<li><a href="filter_iterator.htm">Filter Iterator Adaptor</a>
</ul>
</ul>
<li>Header <tt><a href=
"../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a></tt><br>
<a href="counting_iterator.htm">Counting Iterator Adaptor</a>
<li>Header <tt><a href=
"../../boost/function_output_iterator.hpp">boost/function_output_iterator.hpp</a></tt><br>
<a href="function_output_iterator.htm">Function Output Iterator Adaptor</a>
</ul>
<p><b><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
Abrahams</a></b> started the library, applying <a href=
"../../more/generic_programming.html#policy">policy class</a> technique and
handling const/non-const iterator interactions. He also contributed the
<tt><a href="indirect_iterator.htm">indirect_</a></tt> and <tt><a href=
"reverse_iterator.htm">reverse_</a></tt> iterator generators, and expanded
<tt><a href="counting_iterator.htm">counting_iterator_generator</a></tt> to
cover all incrementable types. He edited most of the documentation,
sometimes heavily.<br>
<b><a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy
Siek</a></b> contributed the <a href="transform_iterator.htm">transform
iterator</a> adaptor, the integer-only version of <tt><a href=
"counting_iterator.htm">counting_iterator_generator</a></tt>,
the <a href="function_output_iterator.htm">function output iterator</a>
adaptor, and most of the documentation.<br>
<b><a href="http://www.boost.org/people/john_potter.htm">John
Potter</a></b> contributed the <tt><a href=
"projection_iterator.htm">projection_</a></tt> and <tt><a href=
"filter_iterator.htm">filter_</a></tt> iterator generators and made some
simplifications to the main <tt><a href=
"#iterator_adaptor">iterator_adaptor</a></tt> template.<br>
<h2><a name="iterator_adaptor">Class template</a>
<tt>iterator_adaptor</tt></h2>
Implementing standard conforming iterators is a non-trivial task. There are
some fine points such as the interactions between an iterator and its
corresponding const_iterator, and there are myriad operators that should be
implemented but are easily forgotten or mishandled, such as
<tt>operator-&gt;()</tt>. Using <tt>iterator_adaptor</tt>, you can easily
implement an iterator class, and even more easily extend and <a href=
"../../more/generic_programming.html#adaptors">adapt</a> existing iterator
types. Moreover, it is easy to make a pair of interoperable <tt>const</tt>
and <tt>non-const</tt> iterators.
<p><tt>iterator_adaptor</tt> is declared like this:
<pre>
template &lt;class Base, class Policies,
class ValueOrNamedParams = typename std::iterator_traits&lt;Base&gt;::value_type,
class ReferenceOrNamedParams = <i>...(see below)</i>,
class PointerOrNamedParams = <i>...(see below)</i>,
class CategoryOrNamedParams = typename std::iterator_traits&lt;Base&gt;::iterator_category,
class DistanceOrNamedParams = typename std::iterator_traits&lt;Base&gt;::difference_type&gt;
struct iterator_adaptor;
</pre>
<h3><a name="template_parameters">Template Parameters</a></h3>
<p>Although <tt>iterator_adaptor</tt> takes seven template parameters,
defaults have been carefully chosen to minimize the number of parameters
you must supply in most cases, especially if <tt>BaseType</tt> is an
iterator.
<table border="1" summary="iterator_adaptor template parameters">
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt>BaseType</tt>
<td>The type being wrapped.
<tr>
<td><tt>Policies</tt>
<td>A <a href="../../more/generic_programming.html#policy">policy
class</a> that supplies core functionality to the resulting iterator. A
detailed description can be found <a href="#policies">below</a>.
<tr>
<td><tt>Value</tt>
<td>The <tt>value_type</tt> of the resulting iterator, unless const. If
Value is <tt>const X</tt> the
<tt>value_type</tt> will be (<i>non-</i><tt>const</tt>) <tt>X</tt><a href=
"#1">[1]</a>. If the <tt>value_type</tt> you wish to use is an abstract
base class see note <a href="#5">[5]</a>.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseType&gt;::value_type</tt> <a href=
"#2">[2]</a>
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&amp;</tt> is
used. Otherwise
<tt>std::iterator_traits&lt;BaseType&gt;::reference</tt> is used.
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise <tt>std::iterator_traits&lt;BaseType&gt;::pointer</tt>.
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseType&gt;::iterator_category</tt>
<tr>
<td><tt>Distance</tt>
<td>The <tt>difference_type</tt> for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseType&gt;::difference_type</tt>
<tr>
<td><tt>NamedParams</tt>
<td>A list of named template parameters generated using the
<a href="#iterator_traits_generator">
<tt>iterator_traits_generator</tt></a> class (see below).
</table>
<h3><a name="named_template_parameters">Named Template Parameters</a></h3>
With seven template parameters, providing arguments for
<tt>iterator_adaptor</tt> in the correct order can be challenging.
Also, often times one would like to specify the sixth or seventh
template parameter, but use the defaults for the third through
fifth. As a solution to these problems we provide a mechanism for
naming the last five template parameters, and providing them in
any order through the <tt>iterator_traits_generator</tt> class.
<blockquote>
<pre>
<a name="iterator_traits_generator">class iterator_traits_generator</a>
{
public:
template &lt;class Value&gt;
struct value_type : public <i>recursive magic</i> { };
template &lt;class Reference&gt;
struct reference : public <i>recursive magic</i> { };
template &lt;class Pointer&gt;
struct pointer : public <i>recursive magic</i> { };
template &lt;class Distance&gt;
struct difference_type : public <i>recursive magic</i> { };
template &lt;class Category&gt;
struct iterator_category : public <i>recursive magic</i> { };
};
</pre>
</blockquote>
The <tt>iterator_traits_generator</tt> is used to create a list of
of template arguments. For example, suppose you want to set the
<tt>Reference</tt> and <tt>Category</tt> parameters, and use the
defaults for the rest. Then you can use the traits generator as
follows:
<blockquote>
<pre>
iterator_traits_generator::reference&lt;foo&gt;::category&lt;std::input_iterator_tag&gt;
</pre>
</blockquote>
This generated type can then be passed into the <tt>iterator_adaptor</tt>
class to replace any of the last five parameters. If you use the traits
generator in the <i>i</i>th parameter position, then the parameters <i>i</i>
through 7 will use the types specified in the generator. For example, the
following adapts <tt>foo_iterator</tt> to create an <a href=
"http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> with
<tt>reference</tt> type <tt>foo</tt>, and whose other traits are determined
according to the defaults described <a href="#template_parameters">above</a>.
<blockquote>
<pre>
iterator_adaptor&lt;foo_iterator, foo_policies,
iterator_traits_generator
::reference&lt;foo&gt;
::iterator_category&lt;std::input_iterator_tag&gt;
&gt;
</pre>
</blockquote>
<h3><a name="policies">The Policies Class</a></h3>
<p>The main task in using <tt>iterator_adaptor</tt> is creating an
appropriate <tt>Policies</tt> class. The <tt>Policies</tt> class will become
the functional heart of the resulting iterator, supplying the core
operations that determine its behavior. The <tt>iterator_adaptor</tt>
template defines all of the operators required of a <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> by dispatching to a <tt>Policies</tt> object. Your
<tt>Policies</tt> class must implement a subset of the core iterator
operations below corresponding to the iterator categories you want it to
support.<br>
<br>
<table border="1" summary="iterator_adaptor Policies operations">
<caption>
<b>Core Iterator Operations</b><br>
<tt>T</tt>: adapted iterator type; <tt>p</tt>: object of type T; <tt>n</tt>: <tt>T::size_type</tt>; <tt>x</tt>: <tt>T::difference_type</tt>; <tt>p1</tt>, <tt>p2</tt>: iterators
</caption>
<tr>
<th>Operation
<th>Effects
<th>Implements Operations
<th>Required for Iterator Categories
<tr>
<td><tt>initialize</tt>
<td>optionally modify base iterator during iterator construction
<td>constructors
<td rowspan="4"><a href=
"http://www.sgi.com/tech/stl/InputIterator.html">Input</a>/ <a href=
"http://www.sgi.com/tech/stl/OutputIterator.html">Output</a>/ <a href=
"http://www.sgi.com/tech/stl/ForwardIterator.html">Forward</a>/ <a
href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional</a>/
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access</a>
<tr>
<td><tt>dereference</tt>
<td>returns an element of the iterator's <tt>reference</tt> type
<td><tt>*p</tt>, <tt>p[n]</tt>
<tr>
<td><tt>equal</tt>
<td>tests the iterator for equality
<td><tt>p1&nbsp;==&nbsp;p2</tt>, <tt>p1&nbsp;!=&nbsp;p2</tt>
<tr>
<td><tt>increment</tt>
<td>increments the iterator
<td><tt>++p</tt>, <tt>p++</tt>
<tr>
<td><tt>decrement</tt>
<td>decrements the iterator
<td><tt>--p</tt>, <tt>p--</tt>
<td><a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional</a>/
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access</a>
<tr>
<td><tt>less</tt>
<td>imposes a <a href=
"http://www.sgi.com/tech/stl/StrictWeakOrdering.html">Strict Weak
Ordering</a> relation on iterators
<td>
<tt>p1&nbsp;&lt;&nbsp;p2</tt>,
<tt>p1&nbsp;&lt;=&nbsp;p2</tt>,
<tt>p1&nbsp;&gt;&nbsp;p2</tt>,
<tt>p1&nbsp;&gt;=&nbsp;p2</tt>
<td rowspan="3"><a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access</a>
<tr>
<td><tt>distance</tt>
<td>measures the distance between iterators
<td><tt>p1 - p2</tt>
<tr>
<td><tt>advance</tt>
<td>adds an integer offset to iterators
<td>
<tt>p&nbsp;+&nbsp;x</tt>,
<tt>x&nbsp;+&nbsp;p</tt>,
<tt>p&nbsp;+=&nbsp;x</tt>,
<tt>p&nbsp;-&nbsp;x</tt>,
<tt>p&nbsp;-=&nbsp;x</tt>
</table>
<p>The library also supplies a "trivial" policy class,
<tt>default_iterator_policies</tt>, which implements all seven of the core
operations in the usual way. If you wish to create an iterator adaptor that
only changes a few of the base type's behaviors, then you can derive your
new policy class from <tt>default_iterator_policies</tt> to avoid retyping
the usual behaviors. You should also look at
<tt>default_iterator_policies</tt> as the ``boilerplate'' for your own
policy classes, defining functions with the same interface. This is the
definition of <tt>default_iterator_policies</tt>:<br>
<br>
<blockquote>
<pre>
struct <a name="default_iterator_policies">default_iterator_policies</a>
{
template &lt;class BaseType&gt;
void initialize(BaseType&amp;)
{ }
template &lt;class Reference, class BaseType&gt;
Reference dereference(type&lt;Reference&gt;, const BaseType&amp; x) const
{ return *x; }
template &lt;class BaseType&gt;
static void increment(BaseType&amp; x)
{ ++x; }
template &lt;class BaseType1, class BaseType2&gt;
bool equal(BaseType1&amp; x, BaseType2&amp; y) const
{ return x == y; }
template &lt;class BaseType&gt;
static void decrement(BaseType&amp; x)
{ --x; }
template &lt;class BaseType, class DifferenceType&gt;
static void advance(BaseType&amp; x, DifferenceType n)
{ x += n; }
template &lt;class Difference, class BaseType1, class BaseType2&gt;
Difference distance(type&lt;Difference&gt;, BaseType1&amp; x, BaseType2&amp; y) const
{ return y - x; }
template &lt;class BaseType1, class BaseType2&gt;
bool less(BaseType1&amp; x, BaseType2&amp; y) const
{ return x &lt; y; }
};
</pre>
</blockquote>
<p>Template member functions are used throughout
<tt>default_iterator_policies</tt> so that it can be employed with a wide
range of iterators. If we had used concrete types above, we'd have tied the
usefulness of <tt>default_iterator_policies</tt> to a particular range of
adapted iterators. If you follow the same pattern with your
<tt>Policies</tt> classes, you can use them to generate more specialized
adaptors along the lines of <a href="#specialized_adaptors">those supplied by this library</a>.
<h3><a name="additional_members">Additional Members</a></h3>
In addition to all of the member functions required of a <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a>, the <tt>iterator_adaptor</tt> class template defines the
following members. <br>
<br>
<table border="1" summary="additional iterator_adaptor members">
<tr>
<td><tt>explicit iterator_adaptor(const Base&amp;, const Policies&amp; =
Policies())</tt>
<br><br>
Construct an adapted iterator from a base object and a policies
object. As this constructor is <tt>explicit</tt>, it does not
provide for implicit conversions from the <tt>Base</tt> type to
the iterator adaptor.
<tr>
<td><tt>template &lt;class B, class V, class R, class P&gt;<br>
iterator_adaptor(const
iterator_adaptor&lt;B,Policies,V,R,P,Category,Distance&gt;&amp;)</tt>
<br><br>
This constructor allows for conversion from non-<tt>const</tt> to
constant adapted iterators. See <a href=
"#iterator_interactions">below</a> for more details.<br>
Requires: <tt>B</tt> is convertible to <tt>Base</tt>.
<tr>
<td><tt>base_type base() const;</tt>
<br><br>
Return a copy of the base object.
</table>
<h3><a name="example">Example</a></h3>
<p>It is often useful to automatically apply some function to the value
returned by dereferencing an iterator. The <a href=
"./transform_iterator.htm">transform iterator</a> makes it easy to create
an iterator adaptor which does just that. Here we will show how easy it is
to implement the transform iterator using the <tt>iterator_adaptor</tt>
template.
<p>We want to be able to adapt a range of iterators and functions, so the
policies class will have a template parameter for the function type and it
will have a data member of that type. We know that the function takes one
argument and that we'll need to be able to deduce the <tt>result_type</tt>
of the function so we can use it for the adapted iterator's
<tt>value_type</tt>. <a href=
"http://www.sgi.com/Technology/STL/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>
is the <a href="../../more/generic_programming.html#concept">Concept</a>
that fulfills those requirements.
<p>To implement a transform iterator we will only change one of the base
iterator's behaviors, so the <tt>transform_iterator_policies</tt> class can
inherit the rest from <tt>default_iterator_policies</tt>. We will define
the <tt>dereference()</tt> member function, which is used to implement
<tt>operator*()</tt> of the adapted iterator. The implementation will
dereference the base iterator and apply the function object. The
<tt>type&lt;Reference&gt;</tt> parameter is used to convey the appropriate
return type. The complete code for <tt>transform_iterator_policies</tt>
is:<br>
<br>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction&gt;
struct transform_iterator_policies : public default_iterator_policies
{
transform_iterator_policies() { }
transform_iterator_policies(const AdaptableUnaryFunction&amp; f)
: m_f(f) { }
template &lt;class Reference, class BaseIterator&gt;
Reference dereference(type&lt;Reference&gt;, const BaseIterator&amp; i) const
{ return m_f(*i); }
AdaptableUnaryFunction m_f;
};
</pre>
</blockquote>
<p>The next step is to use the <tt>iterator_adaptor</tt> template to
construct the transform iterator type. The nicest way to package the
construction of the transform iterator is to create a <a href=
"../../more/generic_programming.html#type_generator">type generator</a>.
The first template parameter to the generator will be the type of the
function object and the second will be the base iterator type. We use
<tt>iterator_adaptor</tt> to define the transform iterator type as a nested
<tt>typedef</tt> inside the <tt>transform_iterator_generator</tt> class.
Because the function may return by-value, we must limit the
<tt>iterator_category</tt> to <a href=
"http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>, and
the iterator's <tt>reference</tt> type cannot be a true reference (the
standard allows this for input iterators), so in this case we can use few
of <tt>iterator_adaptor</tt>'s default template arguments.<br>
<br>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator&gt;
struct transform_iterator_generator
{
typedef typename AdaptableUnaryFunction::result_type value_type;
public:
typedef iterator_adaptor&lt;Iterator,
transform_iterator_policies&lt;AdaptableUnaryFunction&gt;,
value_type, value_type, value_type*, std::input_iterator_tag&gt;
type;
};
</pre>
</blockquote>
<p>As a finishing touch, we will create an <a href=
"../../more/generic_programming.html#object_generator">object generator</a>
for the transform iterator. This is a function that makes it more
convenient to create a transform iterator.<br>
<br>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator&gt;
typename transform_iterator_generator&lt;AdaptableUnaryFunction,Iterator&gt;::type
make_transform_iterator(Iterator base,
const AdaptableUnaryFunction&amp; f = AdaptableUnaryFunction())
{
typedef typename transform_iterator_generator&lt;AdaptableUnaryFunction,
Iterator&gt;::type result_t;
return result_t(base, f);
}
</pre>
</blockquote>
<p>Here is an example that shows how to use a transform iterator to iterate
through a range of numbers, multiplying each of them by 2 and printing the
result to standard output.<br>
<br>
<blockquote>
<pre>
#include &lt;functional&gt;
#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
int main(int, char*[])
{
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int N = sizeof(x)/sizeof(int);
std::cout &lt;&lt; "multiplying the array by 2:" &lt;&lt; std::endl;
std::copy(boost::make_transform_iterator(x, std::bind1st(std::multiplies&lt;int&gt;(), 2)),
boost::make_transform_iterator(x + N, std::bind1st(std::multiplies&lt;int&gt;(), 2)),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
This output is:
<pre>
2 4 6 8 10 12 14 16
</pre>
</blockquote>
<h3><a name="iterator_interactions">Iterator Interactions</a></h3>
<p>C++ allows <tt>const</tt> and non-<tt>const</tt> pointers to interact in
the following intuitive ways:
<ul>
<li>a non-<tt>const</tt> pointer to <tt>T</tt> can be implicitly
converted to a <tt>const</tt> pointer to <tt>T</tt>.
<li><tt>const</tt> and non-<tt>const</tt> pointers to <tt>T</tt> can be
freely mixed in comparison expressions.
<li><tt>const</tt> and non-<tt>const</tt> pointers to <tt>T</tt> can be
freely subtracted, in any order.
</ul>
Getting user-defined iterators to work together that way is nontrivial (see
<a href="reverse_iterator.htm#interactions">here</a> for an example of where
the C++ standard got it wrong), but <tt>iterator_adaptor</tt> can make it
easy. The rules are as follows:
<ul>
<li><a name="interoperable">Adapted iterators that share the same <tt>Policies</tt>,
<tt>Category</tt>, and <tt>Distance</tt> parameters are called
<i>interoperable</i>.</a>
<li>An adapted iterator can be implicitly converted to any other adapted
iterator with which it is interoperable, so long as the <tt>Base</tt>
type of the source iterator can be converted to the <tt>Base</tt> type of
the target iterator.
<li>Interoperable iterators can be freely mixed in comparison expressions
so long as the <tt>Policies</tt> class has <tt>equal</tt> (and, for
random access iterators, <tt>less</tt>) members that can accept both
<tt>Base</tt> types in either order.
<li>Interoperable iterators can be freely mixed in subtraction
expressions so long as the <tt>Policies</tt> class has a
<tt>distance</tt> member that can accept both <tt>Base</tt> types in
either order.
</ul>
<h4>Example</h4>
<p>The <a href="projection_iterator.htm">Projection Iterator</a> adaptor is similar to the <a
href="./transform_iterator.htm">transform iterator adaptor</a> in that
its <tt>operator*()</tt> applies some function to the result of
dereferencing the base iterator and then returns the result. The
difference is that the function must return a reference to some
existing object (for example, a data member within the
<tt>value_type</tt> of the base iterator).
<p>
The <a
href="projection_iterator.htm#projection_iterator_pair_generator">projection_iterator_pair_generator</a> template
is a special two-<a href="../../more/generic_programming.html#type_generator">type generator</a> for mutable and constant versions of a
projection iterator. It is defined as follows:
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator, class ConstIterator&gt;
struct projection_iterator_pair_generator {
typedef typename AdaptableUnaryFunction::result_type value_type;
typedef projection_iterator_policies&lt;AdaptableUnaryFunction&gt; policies;
public:
typedef iterator_adaptor&lt;Iterator,policies,value_type&gt; iterator;
typedef iterator_adaptor&lt;ConstIterator,policies,value_type,
const value_type&amp;,const value_type*&gt; const_iterator;
};
</pre>
</blockquote>
<p>It is assumed that the <tt>Iterator</tt> and <tt>ConstIterator</tt> arguments are corresponding mutable
and constant iterators. <ul>
<li>
Clearly, then, the
<tt>projection_iterator_pair_generator</tt>'s <tt>iterator</tt> and
<tt>const_iterator</tt> are <a href="#interoperable">interoperable</a>, since
they share the same <tt>Policies</tt> and since <tt>Category</tt> and
<tt>Distance</tt> as supplied by <tt>std::iterator_traits</tt> through the
<a href="#template_parameters">default template parameters</a> to
<tt>iterator_adaptor</tt> should be the same.
<li>Since <tt>Iterator</tt> can presumably be converted to
<tt>ConstIterator</tt>, the projection <tt>iterator</tt> will be convertible to
the projection <tt>const_iterator</tt>.
<li> Since <tt>projection_iterator_policies</tt> implements only the
<tt>dereference</tt> operation, and inherits all other behaviors from <tt><a
href="#default_iterator_policies">default_iterator_policies</a></tt>, which has
fully-templatized <tt>equal</tt>, <tt>less</tt>, and <tt>distance</tt>
operations, the <tt>iterator</tt> and <tt>const_iterator</tt> can be freely
mixed in comparison and subtraction expressions.
</ul>
<h3><a name="challenge">Challenge</a></h3>
<p>There is an unlimited number of ways 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><a name="concept_model">Concept Model</a></h3>
Depending on the <tt>Base</tt> and <tt>Policies</tt> template parameters,
an <tt>iterator_adaptor</tt> can be a <a href=
"http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>, <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward
Iterator</a>, <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional
Iterator</a>, or <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a>.
<h3><a name="declaration_synopsis">Declaration Synopsis</a></h3>
<pre>
template &lt;class Base, class Policies,
class Value = typename std::iterator_traits&lt;Base&gt;::value_type,
class Reference = <i>...(see below)</i>,
class Pointer = <i>...(see below)</i>,
class Category = typename std::iterator_traits&lt;Base&gt;::iterator_category,
class Distance = typename std::iterator_traits&lt;Base&gt;::difference_type
&gt;
struct iterator_adaptor
{
typedef Distance difference_type;
typedef typename boost::remove_const&lt;Value&gt;::type value_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
typedef Base base_type;
typedef Policies policies_type;
iterator_adaptor();
explicit iterator_adaptor(const Base&amp;, const Policies&amp; = Policies());
base_type base() const;
template &lt;class B, class V, class R, class P&gt;
iterator_adaptor(
const iterator_adaptor&lt;B,Policies,V,R,P,Category,Distance&gt;&amp;);
reference operator*() const;
<i>operator_arrow_result_type</i> operator-&gt;() const; <a href=
"#3">[3]</a>
<i>value_type</i> operator[](difference_type n) const; <a href="#3">[4]</a>
iterator_adaptor&amp; operator++();
iterator_adaptor&amp; operator++(int);
iterator_adaptor&amp; operator--();
iterator_adaptor&amp; operator--(int);
iterator_adaptor&amp; operator+=(difference_type n);
iterator_adaptor&amp; operator-=(difference_type n);
iterator_adaptor&amp; operator-(Distance x) const;
};
template &lt;class B, class P, class V, class R, class Ptr,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt;
operator+(iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt;, D2);
template &lt;class B, class P, class V, class R, class Ptr,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,P,V,R,P,C,D1&gt;
operator+(D2, iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt; p);
template &lt;class B1, class B2, class P, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
Distance operator-(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class P, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator==(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
// and similarly for operators !=, &lt;, &lt;=, &gt;=, &gt;
</pre>
<h3><a name="notes">Notes</a></h3>
<p><a name="1">[1]</a> The standard specifies that the <tt>value_type</tt>
of <tt>const</tt> iterators to <tt>T</tt> (e.g. <tt>const T*</tt>) is
<tt><i>non-</i>const T</tt>, while the <tt>pointer</tt> and
<tt>reference</tt> types for all <a href=
"http://www.sgi.com/tech/stl/ForwardIterator.html">Forward Iterators</a> are
<tt>const T*</tt> and <tt>const T&amp;</tt>, respectively. Stripping the
<tt>const</tt>-ness of <tt>Value</tt> allows you to easily
make a <tt>const</tt> iterator adaptor by supplying a <tt>const</tt> type
for <tt>Value</tt>, and allowing the defaults for the <tt>Pointer</tt> and
<tt>Reference</tt> parameters to take effect. Although compilers that don't
support partial specialization won't strip <tt>const</tt> for you, having a
<tt>const value_type</tt> is often harmless in practice.
<p><a name="2">[2]</a> If your compiler does not support partial
specialization and the base iterator is a builtin pointer type, you
will not be able to use the default for <tt>Value</tt> and will have to
specify this type explicitly.
<p><a name="3">[3]</a> The result type for the <tt>operator-&gt;()</tt>
depends on the category and value type of the iterator and is somewhat
complicated to describe. But be assured, it works in a stardard conforming
fashion, providing access to members of the objects pointed to by the
iterator.
<p><a name="4">[4]</a> The result type of <tt>operator[]()</tt> is
<tt>value_type</tt> instead of <tt>reference</tt> as might be expected.
There are two reasons for this choice. First, the C++ standard only
requires that the return type of an arbitrary <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a>'s <tt>operator[]</tt>be ``convertible to T'' (Table 76), so
when adapting an arbitrary base iterator we may not have a reference to
return. Second, and more importantly, for certain kinds of iterators,
returning a reference could cause serious memory problems due to the
reference being bound to a temporary object whose lifetime ends inside of
the <tt>operator[]</tt>.
<p><a name="5">[5]</a>
The <tt>value_type</tt> of an iterator may not be
an abstract base class, however many common uses of iterators
never need the <tt>value_type</tt>, only the <tt>reference</tt> type.
If you wish to create such an iterator adaptor, use a dummy
type such as <tt>char</tt> for the <tt>Value</tt> parameter,
and use a reference to your abstract base class for
the <tt>Reference</tt> parameter. Note that such an iterator
does not fulfill the C++ standards requirements for a
<a href= "http://www.sgi.com/tech/stl/ForwardIterator.html">
Forward Iterator</a>, so you will need to use a less restrictive
iterator category such as <tt>std::input_iterator_tag</tt>.
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->19 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14895" -->
<p>&copy; Copyright Dave Abrahams and Jeremy Siek 2001. Permission to copy,
use, modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided "as is"
without express or implied warranty, and with no claim as to its
suitability for any purpose.
</body>
<!-- LocalWords: HTML html charset alt gif abrahams htm const
incrementable david abrahams
-->
<!-- LocalWords: jeremy siek mishandled interoperable typename struct Iter iter src
-->
<!-- LocalWords: int bool ForwardIterator BidirectionalIterator BaseIterator
-->
<!-- LocalWords: RandomAccessIterator DifferenceType AdaptableUnaryFunction
-->
<!-- LocalWords: iostream hpp sizeof InputIterator constness ConstIterator
David Abrahams
-->
</html>

210
iterator_traits_test.cpp Normal file
View File

@@ -0,0 +1,210 @@
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 04 Mar 2001 Patches for Intel C++ (Dave Abrahams)
// 19 Feb 2001 Take advantage of improved iterator_traits to do more tests
// on MSVC. Reordered some #ifdefs for coherency.
// (David Abrahams)
// 13 Feb 2001 Test new VC6 workarounds (David Abrahams)
// 11 Feb 2001 Final fixes for Borland (David Abrahams)
// 11 Feb 2001 Some fixes for Borland get it closer on that compiler
// (David Abrahams)
// 07 Feb 2001 More comprehensive testing; factored out static tests for
// better reuse (David Abrahams)
// 21 Jan 2001 Quick fix to my_iterator, which wasn't returning a
// reference type from operator* (David Abrahams)
// 19 Jan 2001 Initial version with iterator operators (David Abrahams)
#include <boost/detail/iterator.hpp>
#include <boost/type_traits.hpp>
#include <boost/operators.hpp>
#include <boost/static_assert.hpp>
#include <iterator>
#include <vector>
#include <list>
#include <cassert>
#include <iostream>
// An iterator for which we can get traits.
struct my_iterator1
: boost::forward_iterator_helper<my_iterator1, char, long, const char*, const char&>
{
my_iterator1(const char* p) : m_p(p) {}
bool operator==(const my_iterator1& rhs) const
{ return this->m_p == rhs.m_p; }
my_iterator1& operator++() { ++this->m_p; return *this; }
const char& operator*() { return *m_p; }
private:
const char* m_p;
};
// Used to prove that we don't require std::iterator<> in the hierarchy under
// MSVC6, and that we can compute all the traits for a standard-conforming UDT
// iterator.
struct my_iterator2
: boost::equality_comparable<my_iterator2
, boost::incrementable<my_iterator2
, boost::dereferenceable<my_iterator2,const char*> > >
{
typedef char value_type;
typedef long difference_type;
typedef const char* pointer;
typedef const char& reference;
typedef std::forward_iterator_tag iterator_category;
my_iterator2(const char* p) : m_p(p) {}
bool operator==(const my_iterator2& rhs) const
{ return this->m_p == rhs.m_p; }
my_iterator2& operator++() { ++this->m_p; return *this; }
const char& operator*() { return *m_p; }
private:
const char* m_p;
};
// Used to prove that we're not overly confused by the existence of
// std::iterator<> in the hierarchy under MSVC6 - we should find that
// boost::detail::iterator_traits<my_iterator3>::difference_type is int.
struct my_iterator3 : my_iterator1
{
typedef int difference_type;
my_iterator3(const char* p) : my_iterator1(p) {}
};
template <class Iterator,
class value_type, class difference_type, class pointer, class reference, class category>
struct non_portable_tests
{
// Unfortunately, the VC6 standard library doesn't supply these :(
BOOST_STATIC_ASSERT((
boost::is_same<
typename boost::detail::iterator_traits<Iterator>::pointer,
pointer
>::value));
BOOST_STATIC_ASSERT((
boost::is_same<
typename boost::detail::iterator_traits<Iterator>::reference,
reference
>::value));
};
template <class Iterator,
class value_type, class difference_type, class pointer, class reference, class category>
struct portable_tests
{
BOOST_STATIC_ASSERT((
boost::is_same<
typename boost::detail::iterator_traits<Iterator>::difference_type,
difference_type
>::value));
BOOST_STATIC_ASSERT((
boost::is_same<
typename boost::detail::iterator_traits<Iterator>::iterator_category,
category
>::value));
};
// Test iterator_traits
template <class Iterator,
class value_type, class difference_type, class pointer, class reference, class category>
struct input_iterator_test
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
{
BOOST_STATIC_ASSERT((
boost::is_same<
typename boost::detail::iterator_traits<Iterator>::value_type,
value_type
>::value));
};
template <class Iterator,
class value_type, class difference_type, class pointer, class reference, class category>
struct non_pointer_test
: input_iterator_test<Iterator,value_type,difference_type,pointer,reference,category>
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
{
};
template <class Iterator,
class value_type, class difference_type, class pointer, class reference, class category>
struct maybe_pointer_test
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
#endif
{
};
input_iterator_test<std::istream_iterator<int>, int, std::ptrdiff_t, int*, int&, std::input_iterator_tag>
istream_iterator_test;
//
#if defined(__BORLANDC__) && !defined(__SGI_STL_PORT)
typedef ::std::char_traits<char>::off_type distance;
non_pointer_test<std::ostream_iterator<int>,int,
distance,int*,int&,std::output_iterator_tag> ostream_iterator_test;
#elif defined(BOOST_MSVC_STD_ITERATOR)
non_pointer_test<std::ostream_iterator<int>,
int, void, void, void, std::output_iterator_tag>
ostream_iterator_test;
#else
non_pointer_test<std::ostream_iterator<int>,
void, void, void, void, std::output_iterator_tag>
ostream_iterator_test;
#endif
#ifdef __KCC
typedef long std_list_diff_type;
#else
typedef std::ptrdiff_t std_list_diff_type;
#endif
non_pointer_test<std::list<int>::iterator, int, std_list_diff_type, int*, int&, std::bidirectional_iterator_tag>
list_iterator_test;
maybe_pointer_test<std::vector<int>::iterator, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
vector_iterator_test;
maybe_pointer_test<int*, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
int_pointer_test;
non_pointer_test<my_iterator1, char, long, const char*, const char&, std::forward_iterator_tag>
my_iterator1_test;
non_pointer_test<my_iterator2, char, long, const char*, const char&, std::forward_iterator_tag>
my_iterator2_test;
non_pointer_test<my_iterator3, char, int, const char*, const char&, std::forward_iterator_tag>
my_iterator3_test;
int main()
{
char chars[100];
int ints[100];
for (std::ptrdiff_t length = 3; length < 100; length += length / 3)
{
std::list<int> l(length);
assert(boost::detail::distance(l.begin(), l.end()) == length);
std::vector<int> v(length);
assert(boost::detail::distance(v.begin(), v.end()) == length);
assert(boost::detail::distance(&ints[0], ints + length) == length);
assert(boost::detail::distance(my_iterator1(chars), my_iterator1(chars + length)) == length);
assert(boost::detail::distance(my_iterator2(chars), my_iterator2(chars + length)) == length);
assert(boost::detail::distance(my_iterator3(chars), my_iterator3(chars + length)) == length);
}
return 0;
}

169
iterators_test.cpp Normal file
View File

@@ -0,0 +1,169 @@
// 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;
}

38
noncopyable_test.cpp Normal file
View File

@@ -0,0 +1,38 @@
// 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

393
numeric_traits_test.cpp Normal file
View File

@@ -0,0 +1,393 @@
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 11 Feb 2001 Fixes for Borland (David Abrahams)
// 23 Jan 2001 Added test for wchar_t (David Abrahams)
// 23 Jan 2001 Now statically selecting a test for signed numbers to avoid
// warnings with fancy compilers. Added commentary and
// additional dumping of traits data for tested types (David
// Abrahams).
// 21 Jan 2001 Initial version (David Abrahams)
#include <boost/detail/numeric_traits.hpp>
#include <cassert>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/lexical_cast.hpp>
#include <climits>
#include <typeinfo>
#include <iostream>
#include <string>
#ifndef BOOST_NO_LIMITS
# include <limits>
#endif
// A macro for declaring class compile-time constants.
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
# define DECLARE_CLASS_CONST(type, init) static const type init
#else
# define DECLARE_CLASS_CONST(type, init) enum { init }
#endif
// =================================================================================
// template class complement_traits<Number> --
//
// statically computes the max and min for 1s and 2s-complement binary
// numbers. This helps on platforms without <limits> support. It also shows
// an example of a recursive template that works with MSVC!
//
template <unsigned size> struct complement; // forward
// The template complement, below, does all the real work, using "poor man's
// partial specialization". We need complement_traits_aux<> so that MSVC doesn't
// complain about undefined min/max as we're trying to recursively define them.
template <class Number, unsigned size>
struct complement_traits_aux
{
DECLARE_CLASS_CONST(Number, max = complement<size>::template traits<Number>::max);
DECLARE_CLASS_CONST(Number, min = complement<size>::template traits<Number>::min);
};
template <unsigned size>
struct complement
{
template <class Number>
struct traits
{
private:
// indirection through complement_traits_aux neccessary to keep MSVC happy
typedef complement_traits_aux<Number, size - 1> prev;
public:
DECLARE_CLASS_CONST(Number, max =
Number(Number(prev::max) << CHAR_BIT)
+ Number(UCHAR_MAX));
DECLARE_CLASS_CONST(Number, min = Number(Number(prev::min) << CHAR_BIT));
};
};
// Template class complement_base<> -- defines values for min and max for
// complement<1>, at the deepest level of recursion. Uses "poor man's partial
// specialization" again.
template <bool is_signed> struct complement_base;
template <> struct complement_base<false>
{
template <class Number>
struct values
{
DECLARE_CLASS_CONST(Number, min = 0);
DECLARE_CLASS_CONST(Number, max = UCHAR_MAX);
};
};
template <> struct complement_base<true>
{
template <class Number>
struct values
{
DECLARE_CLASS_CONST(Number, min = SCHAR_MIN);
DECLARE_CLASS_CONST(Number, max = SCHAR_MAX);
};
};
// Base specialization of complement, puts an end to the recursion.
template <>
struct complement<1>
{
template <class Number>
struct traits
{
DECLARE_CLASS_CONST(bool, is_signed = boost::detail::is_signed<Number>::value);
DECLARE_CLASS_CONST(Number, min =
complement_base<is_signed>::template values<Number>::min);
DECLARE_CLASS_CONST(Number, max =
complement_base<is_signed>::template values<Number>::max);
};
};
// Now here's the "pretty" template you're intended to actually use.
// complement_traits<Number>::min, complement_traits<Number>::max are the
// minimum and maximum values of Number if Number is a built-in integer type.
template <class Number>
struct complement_traits
{
DECLARE_CLASS_CONST(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
DECLARE_CLASS_CONST(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
};
// =================================================================================
// Support for streaming various numeric types in exactly the format I want. I
// needed this in addition to all the assertions so that I could see exactly
// what was going on.
//
// Numbers go through a 2-stage conversion process (by default, though, no real
// conversion).
//
template <class T> struct stream_as {
typedef T t1;
typedef T t2;
};
// char types first get converted to unsigned char, then to unsigned.
template <> struct stream_as<char> {
typedef unsigned char t1;
typedef unsigned t2;
};
template <> struct stream_as<unsigned char> {
typedef unsigned char t1; typedef unsigned t2;
};
template <> struct stream_as<signed char> {
typedef unsigned char t1; typedef unsigned t2;
};
#if defined(BOOST_MSVC) // No intmax streaming built-in
// On this platform, __int64 and __uint64 get streamed as strings
template <> struct stream_as<boost::uintmax_t> {
typedef std::string t1;
typedef std::string t2;
};
template <> struct stream_as<boost::intmax_t> {
typedef std::string t1;
typedef std::string t2;
};
#endif
// Standard promotion process for streaming
template <class T> struct promote
{
static typename stream_as<T>::t1 from(T x) {
typedef typename stream_as<T>::t1 t1;
return t1(x);
}
};
#if defined(BOOST_MSVC) // No intmax streaming built-in
// On this platform, stream them as long/unsigned long if they fit.
// Otherwise, write a string.
template <> struct promote<boost::uintmax_t> {
std::string static from(const boost::uintmax_t x) {
if (x > ULONG_MAX)
return std::string("large unsigned value");
else
return boost::lexical_cast<std::string>((unsigned long)x);
}
};
template <> struct promote<boost::intmax_t> {
std::string static from(const boost::intmax_t x) {
if (x > boost::intmax_t(ULONG_MAX))
return std::string("large positive signed value");
else if (x >= 0)
return boost::lexical_cast<std::string>((unsigned long)x);
if (x < boost::intmax_t(LONG_MIN))
return std::string("large negative signed value");
else
return boost::lexical_cast<std::string>((long)x);
}
};
#endif
// This is the function which converts types to the form I want to stream them in.
template <class T>
typename stream_as<T>::t2 stream_number(T x)
{
return promote<T>::from(x);
}
// =================================================================================
//
// Tests for built-in signed and unsigned types
//
// Tag types for selecting tests
struct unsigned_tag {};
struct signed_tag {};
// Tests for unsigned numbers. The extra default Number parameter works around
// an MSVC bug.
template <class Number>
void test_aux(unsigned_tag, Number* = 0)
{
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
BOOST_STATIC_ASSERT(
(sizeof(Number) < sizeof(boost::intmax_t))
| (boost::is_same<difference_type, boost::intmax_t>::value));
// Force casting to Number here to work around the fact that it's an enum on MSVC
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) == Number(0));
const Number max = complement_traits<Number>::max;
const Number min = complement_traits<Number>::min;
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
? max
: max / 2 - 1;
std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = "
<< stream_number(max) << "..." << std::flush;
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
<< std::flush;
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
<< std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
assert(d1 == difference_type(test_max));
assert(d2 == -difference_type(test_max));
}
// Tests for signed numbers. The extra default Number parameter works around an
// MSVC bug.
struct out_of_range_tag {};
struct in_range_tag {};
// This test morsel gets executed for numbers whose difference will always be
// representable in intmax_t
template <class Number>
void signed_test(in_range_tag, Number* = 0)
{
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
const Number max = complement_traits<Number>::max;
const Number min = complement_traits<Number>::min;
difference_type d1 = boost::detail::numeric_distance(min, max);
difference_type d2 = boost::detail::numeric_distance(max, min);
std::cout << stream_number(min) << "->" << stream_number(max) << "==";
std::cout << std::dec << stream_number(d1) << "; ";
std::cout << std::hex << stream_number(max) << "->" << stream_number(min)
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
assert(d1 == difference_type(max) - difference_type(min));
assert(d2 == difference_type(min) - difference_type(max));
}
// This test morsel gets executed for numbers whose difference may exceed the
// capacity of intmax_t.
template <class Number>
void signed_test(out_of_range_tag, Number* = 0)
{
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
const Number max = complement_traits<Number>::max;
const Number min = complement_traits<Number>::min;
difference_type min_distance = complement_traits<difference_type>::min;
difference_type max_distance = complement_traits<difference_type>::max;
const Number n1 = Number(min + max_distance);
const Number n2 = Number(max + min_distance);
difference_type d1 = boost::detail::numeric_distance(min, n1);
difference_type d2 = boost::detail::numeric_distance(max, n2);
std::cout << stream_number(min) << "->" << stream_number(n1) << "==";
std::cout << std::dec << stream_number(d1) << "; ";
std::cout << std::hex << stream_number(max) << "->" << stream_number(n2)
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
assert(d1 == max_distance);
assert(d2 == min_distance);
}
template <class Number>
void test_aux(signed_tag, Number* = 0)
{
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
BOOST_STATIC_ASSERT(
(sizeof(Number) < sizeof(boost::intmax_t))
| (boost::is_same<difference_type, Number>::value));
// Force casting to Number here to work around the fact that it's an enum on MSVC
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
const Number max = complement_traits<Number>::max;
const Number min = complement_traits<Number>::min;
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
<< stream_number(max) << "..." << std::flush;
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
<< std::flush;
typedef typename boost::detail::if_true<
(sizeof(Number) < sizeof(boost::intmax_t))>
::template then<
in_range_tag,
out_of_range_tag
>::type
range_tag;
signed_test<Number>(range_tag());
}
// Test for all numbers. The extra default Number parameter works around an MSVC
// bug.
template <class Number>
void test(Number* = 0)
{
std::cout << "testing " << typeid(Number).name() << ":\n"
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
<< "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n")
<< "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n")
<< "digits: " << std::numeric_limits<Number>::digits << "\n"
#endif
<< "..." << std::flush;
// factoring out difference_type for the assert below confused Borland :(
typedef boost::detail::is_signed<
#ifndef BOOST_MSVC
typename
#endif
boost::detail::numeric_traits<Number>::difference_type
> is_signed;
BOOST_STATIC_ASSERT(is_signed::value);
typedef typename boost::detail::if_true<
boost::detail::is_signed<Number>::value
>::template then<signed_tag, unsigned_tag>::type signedness;
test_aux<Number>(signedness());
std::cout << "passed" << std::endl;
}
int main()
{
test<char>();
test<unsigned char>();
test<signed char>();
test<wchar_t>();
test<short>();
test<unsigned short>();
test<int>();
test<unsigned int>();
test<long>();
test<unsigned long>();
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
test<long long>();
test<unsigned long long>();
#elif defined(BOOST_MSVC)
// The problem of not having compile-time static class constants other than
// enums prevents this from working, since values get truncated.
// test<boost::uintmax_t>();
// test<boost::intmax_t>();
#endif
return 0;
}

597
operators.htm Normal file
View File

@@ -0,0 +1,597 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Header boost/operators.hpp Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
<a href="../../boost/operators.hpp">boost/operators.hpp</a></h1>
<p>Header <a href="../../boost/operators.hpp">boost/operators.hpp</a> supplies
(in namespace boost) several sets of templates:</p>
<ul>
<li><a href="#Arithmetic">Arithmetic operators</a>.
<li><a href="#deref and helpers">Dereference operators and iterator helpers.</a></li>
</ul>
<p>These templates define many global operators in terms of a minimal number of
fundamental operators.</p>
<h1><a name="Arithmetic">Arithmetic</a> Operators</h1>
<p>If, for example, you declare a class like this:</p>
<blockquote>
<pre>class MyInt : boost::operators&lt;MyInt&gt;
{
bool operator&lt;(const MyInt&amp; x) const;
bool operator==(const MyInt&amp; x) const;
MyInt&amp; operator+=(const MyInt&amp; x);
MyInt&amp; operator-=(const MyInt&amp; x);
MyInt&amp; operator*=(const MyInt&amp; x);
MyInt&amp; operator/=(const MyInt&amp; x);
MyInt&amp; operator%=(const MyInt&amp; x);
MyInt&amp; operator|=(const MyInt&amp; x);
MyInt&amp; operator&amp;=(const MyInt&amp; x);
MyInt&amp; operator^=(const MyInt&amp; x);
MyInt&amp; operator++();
MyInt&amp; operator--();
};</pre>
</blockquote>
<p>then the <code>operators&lt;&gt;</code> template adds more than a dozen
additional operators, such as operator&gt;, &lt;=, &gt;=, and +.&nbsp; <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 &lt; y,</code> you also want <code>x &gt; y,
x &gt;= y,</code> and <code>x &lt;= 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 &gt;= y <b>&lt;=&gt;</b> !(x &lt; 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&nbsp;+&nbsp;U</code>
is of type <code>T</code>, then <code>T</code> (not <code>U</code>) should be
derived from <code>addable&lt;T,U&gt;</code>. The comparison templates <code><a href="#less_than_comparable">less_than_comparable&lt;&gt;</a></code>
and <code><a href="#equality_comparable">equality_comparable&lt;&gt;</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&lt;&gt;</code></a>
and <a href="#operators"><code>operators2&lt;&gt;</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&lt;T&gt;</code></td>
<td>All the other &lt;T&gt; templates in this table.</td>
<td>All the &lt;T&gt; requirements in this table.</td>
<tr>
<td><code>operators&lt;T,U&gt;<br>
operators2&lt;T,U&gt;</code></td>
<td>All the other &lt;T,U&gt; templates in this table, plus incrementable&lt;T&gt;
and decrementable&lt;T&gt;.</td>
<td><b>All</b> the &lt;T,U&gt; requirements in this table</a><a href="#portability">*</a>,
plus incrementable&lt;T&gt; and decrementable&lt;T&gt;.</td>
</tr>
<a name="less_than_comparable">
<tr>
<td><code>less_than_comparable&lt;T&gt;<br>
less_than_comparable1&lt;T&gt;</code></td>
<td><code>bool operator&gt;(const T&amp;, const T&amp;)&nbsp;<br>
bool operator&lt;=(const T&amp;, const T&amp;)<br>
bool operator&gt;=(const T&amp;, const T&amp;)</code></td>
<td><code>t&lt;t1</code>. Return convertible to bool</td>
<tr>
<td><code>less_than_comparable&lt;T,U&gt;<br>
less_than_comparable2&lt;T,U&gt;</code></td>
<td><code>bool operator&lt;=(const T&amp;, const U&amp;)<br>
bool operator&gt;=(const T&amp;, const U&amp;)<br>
bool operator&gt;(const U&amp;, const T&amp;)&nbsp;<br>
bool operator&lt;(const U&amp;, const T&amp;)&nbsp;<br>
bool operator&lt;=(const U&amp;, const T&amp;)<br>
bool operator&gt;=(const U&amp;, const T&amp;)</code></td>
<td><code>t&lt;u</code>. Return convertible to bool<br>
<code>t&gt;u</code>. Return convertible to bool</td>
</tr>
</a><a name="equality_comparable">
<tr>
<td><code>equality_comparable&lt;T&gt;<br>
equality_comparable1&lt;T&gt;</code></td>
<td><code>bool operator!=(const T&amp;, const T&amp;)</code></td>
<td><code>t==t1</code>. Return convertible to bool</td>
<tr>
<td><code>equality_comparable&lt;T,U&gt;<br>
equality_comparable2&lt;T,U&gt;</code></td>
<td><code>friend bool operator==(const U&amp;, const T&amp;)<br>
friend bool operator!=(const U&amp;, const T&amp;)<br>
friend bool operator!=( const T&amp;, const U&amp;)</code></td>
<td><code>t==u</code>. Return convertible to bool</td>
</tr>
</a>
<tr>
<td><code>addable&lt;T&gt;<br>
addable1&lt;T&gt;</code></td>
<td><code>T operator+(T, const T&amp;)</code></td>
<td><code>t+=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>addable&lt;T,U&gt;<br>
addable2&lt;T,U&gt;</code></td>
<td><code>T operator+(T, const U&amp;)<br>
T operator+(const U&amp;, T )</code></td>
<td><code>t+=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>subtractable&lt;T&gt;<br>
subtractable1&lt;T&gt;</code></td>
<td><code>T operator-(T, const T&amp;)</code></td>
<td><code>t-=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>subtractable&lt;T,U&gt;<br>
subtractable2&lt;T,U&gt;</code></td>
<td><code>T operator-(T, const U&amp;)</code></td>
<td><code>t-=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>multipliable&lt;T&gt;<br>
multipliable1&lt;T&gt;</code></td>
<td><code>T operator*(T, const T&amp;)</code></td>
<td><code>t*=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>multipliable&lt;T,U&gt;<br>
multipliable2&lt;T,U&gt;</code></td>
<td><code>T operator*(T, const U&amp;)<br>
T operator*(const U&amp;, T )</code></td>
<td><code>t*=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>dividable&lt;T&gt;<br>
dividable1&lt;T&gt;</code></td>
<td><code>T operator/(T, const T&amp;)</code></td>
<td><code>t/=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>dividable&lt;T,U&gt;<br>
dividable2&lt;T,U&gt;</code></td>
<td><code>T operator/(T, const U&amp;)</code></td>
<td><code>t/=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>modable&lt;T&gt;<br>
modable1&lt;T&gt;</code></td>
<td><code>T operator%(T, const T&amp;)</code></td>
<td><code>t%=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>modable&lt;T,U&gt;<br>
modable2&lt;T,U&gt;</code></td>
<td><code>T operator%(T, const U&amp;)</code></td>
<td><code>t%=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>orable&lt;T&gt;<br>
orable1&lt;T&gt;</code></td>
<td><code>T operator|(T, const T&amp;)</code></td>
<td><code>t|=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>orable&lt;T,U&gt;<br>
orable2&lt;T,U&gt;</code></td>
<td><code>T operator|(T, const U&amp;)<br>
T operator|(const U&amp;, T )</code></td>
<td><code>t|=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>andable&lt;T&gt;<br>
andable1&lt;T&gt;</code></td>
<td><code>T operator&amp;(T, const T&amp;)</code></td>
<td><code>t&amp;=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>andable&lt;T,U&gt;<br>
andable2&lt;T,U&gt;</code></td>
<td><code>T operator&amp;(T, const U&amp;)<br>
T operator&amp;(const U&amp;, T)</code></td>
<td><code>t&amp;=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>xorable&lt;T&gt;<br>
xorable1&lt;T&gt;</code></td>
<td><code>T operator^(T, const T&amp;)</code></td>
<td><code>t^=t1</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>xorable&lt;T,U&gt;<br>
xorable2&lt;T,U&gt;</code></td>
<td><code>T operator^(T, const U&amp;)<br>
T operator^(const U&amp;, T )</code></td>
<td><code>t^=u</code>. Return convertible to <code>T</code></td>
</tr>
<tr>
<td><code>incrementable&lt;T&gt;<br>
incrementable1&lt;T&gt;</code></td>
<td><code>T operator++(T&amp; 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&lt;T&gt;<br>
decrementable1&lt;T&gt;</code></td>
<td><code>T operator--(T&amp; 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&lt;&gt;</code></a>
and <a href="#operators"><code>operators2&lt;&gt;</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&lt;&gt;</code></a>
and <a href="#operators"><code>operators2&lt;&gt;</code></a> has an additional
optional template parameter <code>B</code>.&nbsp; 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&lt;myclass&gt;;
template class equality_comparable&lt;myclass&gt;;
template class incrementable&lt;myclass&gt;;
template class decrementable&lt;myclass&gt;;
template class addable&lt;myclass,long&gt;;
template class subtractable&lt;myclass,long&gt;;
</pre>
</a><a name="usage">
<h2>Usage example</h2>
</a>
<pre>template &lt;class T&gt;
class point // note: private inheritance is OK here!
: boost::addable&lt; point&lt;T&gt; // point + point
, boost::subtractable&lt; point&lt;T&gt; // point - point
, boost::dividable2&lt; point&lt;T&gt;, T // point / T
, boost::multipliable2&lt; point&lt;T&gt;, T // point * T, T * point
&gt; &gt; &gt; &gt;
{
public:
point(T, T);
T x() const;
T y() const;
point operator+=(const point&amp;);
// point operator+(point, const point&amp;) automatically
// generated by addable.
point operator-=(const point&amp;);
// point operator-(point, const point&amp;) automatically
// generated by subtractable.
point operator*=(T);
// point operator*(point, const T&amp;) and
// point operator*(const T&amp;, point) auto-generated
// by multipliable.
point operator/=(T);
// point operator/(point, const T&amp;) auto-generated
// by dividable.
private:
T x_;
T y_;
};
// now use the point&lt;&gt; class:
template &lt;class T&gt;
T length(const point&lt;T&gt; p)
{
return sqrt(p.x()*p.x() + p.y()*p.y());
}
const point&lt;float&gt; right(0, 1);
const point&lt;float&gt; up(1, 0);
const point&lt;float&gt; pi_over_4 = up + right;
const point&lt;float&gt; 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:&nbsp;</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 &quot;redundant&quot; 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-&gt;</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 &quot;points to&quot;, 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&lt;const T&amp;&gt;(*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.&nbsp;</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&lt;T,P&gt;</code></td>
<td><code>P operator-&gt;() const</code></td>
<td><code>(&amp;*i.)</code>. Return convertible to <code>P</code>.</td>
</tr>
<tr>
<td><code>indexable&lt;T,D,R&gt;</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>&lt;T,V,D,P,R&gt;</code></td>
<td><code>bool operator!=(const T&amp; x1, const T&amp; x2)</code><br>
<code>T operator++(T&amp; x, int)</code><br>
<code>V* operator-&gt;() const</code><br>
</td>
<td><code>x1==x2</code>. Return convertible to bool<br>
<code>T temp(x); ++x; return temp;</code><br>
<code>(&amp;*i.)</code>. Return convertible to <code>V*</code>.</td>
</tr>
<tr>
<td><code>bidirectional_iterator_helper</code><br>
<code>&lt;T,V,D,P,R&gt;</code></td>
<td>Same as above, plus<br>
<code>T operator--(T&amp; 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>&lt;T,V,D,P,R&gt;</code></td>
<td>Same as above, plus<br>
<code>T operator+(T x, const D&amp;)<br>
T operator+(const D&amp; n, T x)<br>
T operator-(T x, const D&amp; n)<br>
R operator[](D n) const<br>
bool operator&gt;(const T&amp; x1, const T&amp; x2)&nbsp;<br>
bool operator&lt;=(const T&amp; x1, const T&amp; x2)<br>
bool operator&gt;=(const T&amp; x1, const T&amp; 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&lt;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
&quot;fill in&quot; the rest of the iterator operations.</p>
<blockquote>
<pre>template &lt;class T, class R, class P&gt;
struct test_iter
: public boost::random_access_iterator_helper&lt;
test_iter&lt;T,R,P&gt;, T, std::ptrdiff_t, P, R&gt;
{
typedef test_iter self;
typedef R Reference;
typedef std::ptrdiff_t Distance;
public:
test_iter(T* i) : _i(i) { }
test_iter(const self&amp; x) : _i(x._i) { }
self&amp; operator=(const self&amp; x) { _i = x._i; return *this; }
Reference operator*() const { return *_i; }
self&amp; operator++() { ++_i; return *this; }
self&amp; operator--() { --_i; return *this; }
self&amp; operator+=(Distance n) { _i += n; return *this; }
self&amp; operator-=(Distance n) { _i -= n; return *this; }
bool operator==(const self&amp; x) const { return _i == x._i; }
bool operator&lt;(const self&amp; x) const { return _i &lt; x._i; }
friend Distance operator-(const self&amp; x, const self&amp; 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.&nbsp; He also contributed <a href="http://www.boost.org/libs/utility/iterators_test.cpp">iterators_test.cpp</a>.&nbsp;</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&lt;int&gt;</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, &quot;One of
the few times when you have the freedom to do this sort of thing is when you're
targeting a new architecture...&quot;. 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&lt;&gt;</code>),
and the forces described above, we decided to change the library interface so
that the object size bloat could be eliminated even on compilers that support
only the simplest form of the empty base class optimization. The current library
interface is the result of those changes. Though the new usage is a bit more
complicated than the old one, we think it's worth it to make the library more
useful in real world. Alexy Gurtovoy contributed the code which supports the new
usage idiom while allowing the library remain backward-compatible.</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->10 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14373" --></p>
<p><EFBFBD> Copyright David Abrahams and Beman Dawes 1999-2000. Permission to copy,
use, modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided &quot;as
is&quot; without express or implied warranty, and with no claim as to its
suitability for any purpose.</p>
</body>
</html>

481
operators_test.cpp Normal file
View File

@@ -0,0 +1,481 @@
// 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;
}

391
projection_iterator.htm Normal file
View File

@@ -0,0 +1,391 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Projection Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Projection Iterator Adaptor</h1>
Defined in header
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>
The projection iterator adaptor is similar to the <a
href="./transform_iterator.htm">transform iterator adaptor</a> in that
its <tt>operator*()</tt> applies some function to the result of
dereferencing the base iterator and then returns the result. The
difference is that the function must return a reference to some
existing object (for example, a data member within the
<tt>value_type</tt> of the base iterator). The following
<b>pseudo-code</b> gives the basic idea. The data member <tt>p</tt> is
the function object.
<pre>
reference projection_iterator::operator*() const {
return this->p(*this->base_iterator);
}
</pre>
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
struct projection_iterator_generator;
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>,
class BaseIterator, class ConstBaseIterator&gt;
struct projection_iterator_pair_generator;
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
typename projection_iterator_generator&lt;AdaptableUnaryFunction, BaseIterator&gt;::type
make_projection_iterator(BaseIterator base,
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator&gt;
typename projection_iterator_generator&lt;AdaptableUnaryFunction, ConstBaseIterator&gt;::type
make_const_projection_iterator(ConstBaseIterator base,
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
}
</pre>
<hr>
<h2><a name="projection_iterator_generator">The Projection Iterator Type
Generator</a></h2>
The class <tt>projection_iterator_generator</tt> is a helper class
whose purpose is to construct an projection iterator type. The main
template parameter for this class is the <a
href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a>
function object type and the <tt>BaseIterator</tt> type that is being
wrapped.
<pre>
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
class projection_iterator_generator
{
public:
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt...&gt;</tt> type; // the resulting projection iterator type
};
</pre>
<h3>Example</h3>
In the following example we have a list of personnel records. Each
record has an employee's name and ID number. We want to be able to
traverse through the list accessing either the name or the ID numbers
of the employees using the projection iterator so we create the
function object classes <tt>select_name</tt> and
<tt>select_ID</tt>. We then use the
<tt>projection_iterator_generator</tt> class to create a projection
iterator and use it to print out the names of the employees.
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;list&gt;
#include &lt;iostream&gt;
#include &lt;iterator&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
struct personnel_record {
personnel_record(std::string n, int id) : m_name(n), m_ID(id) { }
std::string m_name;
int m_ID;
};
struct select_name {
typedef personnel_record argument_type;
typedef std::string result_type;
const std::string&amp; operator()(const personnel_record&amp; r) const {
return r.m_name;
}
std::string&amp; operator()(personnel_record&amp; r) const {
return r.m_name;
}
};
struct select_ID {
typedef personnel_record argument_type;
typedef int result_type;
const int&amp; operator()(const personnel_record&amp; r) const {
return r.m_ID;
}
int&amp; operator()(personnel_record&amp; r) const {
return r.m_ID;
}
};
int main(int, char*[])
{
std::list&lt;personnel_record&gt; personnel_list;
personnel_list.push_back(personnel_record("Barney", 13423));
personnel_list.push_back(personnel_record("Fred", 12343));
personnel_list.push_back(personnel_record("Wilma", 62454));
personnel_list.push_back(personnel_record("Betty", 20490));
// Example of using projection_iterator_generator
// to print out the names in the personnel list.
boost::projection_iterator_generator&lt;select_name,
std::list&lt;personnel_record&gt;::iterator&gt;::type
personnel_first(personnel_list.begin()),
personnel_last(personnel_list.end());
std::copy(personnel_first, personnel_last,
std::ostream_iterator&lt;std::string&gt;(std::cout, "\n"));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
The output for this part is:
<pre>
Barney
Fred
Wilma
Betty
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
<TD>The type of the function object. The <tt>argument_type</tt> of the
function must match the value type of the base iterator. The function
should return a reference to the function's <tt>result_type</tt>.
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
</TD>
</TD>
<TR>
<TD><tt>BaseIterator</tt></TD>
<TD>The iterator type being wrapped.</TD>
</TD>
</TR>
</Table>
<h3>Model of</h3>
If the base iterator is a model of <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> then so is the resulting projection iterator. If
the base iterator supports less functionality than this the resulting
projection iterator will also support less functionality.
<h3>Members</h3>
The projection iterator type implements the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> concept.
In addition it has the following constructor:
<pre>
projection_iterator_generator::type(const BaseIterator&amp; it,
const AdaptableUnaryFunction&amp; p = AdaptableUnaryFunction())
</pre>
<p>
<hr>
<p>
<h2><a name="projection_iterator_pair_generator">The Projection Iterator Pair
Generator</a></h2>
Sometimes a mutable/const pair of iterator types is needed, such as
when implementing a container type. The
<tt>projection_iterator_pair_generator</tt> class makes it more
convenient to create this pair of iterator types.
<pre>
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator, class ConstBaseIterator&gt;
class projection_iterator_pair_generator
{
public:
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt...&gt;</tt> iterator; // the mutable projection iterator type
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt...&gt;</tt> const_iterator; // the immutable projection iterator type
};
</pre>
<h3>Example</h3>
In this part of the example we use the
<tt>projection_iterator_pair_generator</tt> to create a mutable/const
pair of projection iterators that access the ID numbers of the
personnel. We use the mutable iterator to re-index the ID numbers from
zero. We then use the constant iterator to print the ID numbers out.
<pre>
// continuing from the last example...
typedef boost::projection_iterator_pair_generator&lt;select_ID,
std::list&lt;personnel_record&gt;::iterator,
std::list&lt;personnel_record&gt;::const_iterator&gt; PairGen;
PairGen::iterator ID_first(personnel_list.begin()),
ID_last(personnel_list.end());
int new_id = 0;
while (ID_first != ID_last) {
*ID_first = new_id++;
++ID_first;
}
PairGen::const_iterator const_ID_first(personnel_list.begin()),
const_ID_last(personnel_list.end());
std::copy(const_ID_first, const_ID_last,
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
std::cout &lt;&lt; std::endl;
// to be continued...
</pre&gt;
The output is:
<pre>
0 1 2 3
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
<TD>The type of the function object. The <tt>argument_type</tt> of the
function must match the value type of the base iterator. The function
should return a true reference to the function's <tt>result_type</tt>.
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
</TD>
</TD>
<TR>
<TD><tt>BaseIterator</tt></TD>
<TD>The mutable iterator type being wrapped.</TD>
</TD>
</TR>
<TR>
<TD><tt>ConstBaseIterator</tt></TD>
<TD>The constant iterator type being wrapped.</TD>
</TD>
</TR>
</Table>
<h3>Model of</h3>
If the base iterator types model the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> then so do the resulting projection iterator
types. If the base iterators support less functionality the
resulting projection iterator types will also support less
functionality. The resulting <tt>iterator</tt> type is mutable, and
the resulting <tt>const_iterator</tt> type is constant.
<h3>Members</h3>
The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types
implements the member functions and operators required of the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> concept. In addition they support the following
constructors:
<pre>
projection_iterator_pair_generator::iterator(const BaseIterator&amp; it,
const AdaptableUnaryFunction&amp; p = AdaptableUnaryFunction())</pre>
<pre>
projection_iterator_pair_generator::const_iterator(const BaseIterator&amp; it,
const AdaptableUnaryFunction&amp; p = AdaptableUnaryFunction())
</pre>
<p>
<hr>
<p>
<h2><a name="make_projection_iterator">The Projection Iterator Object Generators</a></h2>
The <tt>make_projection_iterator()</tt> and
<tt>make_const_projection_iterator()</tt> functions provide a more
convenient way to create projection iterator objects. The functions
save the user the trouble of explicitly writing out the iterator
types.
<pre>
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
typename projection_iterator_generator&lt;AdaptableUnaryFunction, BaseIterator&gt;::type
make_projection_iterator(BaseIterator base,
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator&gt;
typename projection_iterator_generator&lt;AdaptableUnaryFunction, ConstBaseIterator&gt;::type
make_const_projection_iterator(ConstBaseIterator base,
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
</pre>
<h3>Example</h3>
In this part of the example, we again print out the names of the
personnel, but this time we use the
<tt>make_const_projection_iterator()</tt> function to save some typing.
<pre>
// continuing from the last example...
std::copy
(boost::make_const_projection_iterator&lt;select_name&gt;(personnel_list.begin()),
boost::make_const_projection_iterator&lt;select_name&gt;(personnel_list.end()),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
</pre>
The output is:
<pre>
Barney
Fred
Wilma
Betty
</pre>
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>
<!-- LocalWords: html charset alt gif hpp BaseIterator const namespace struct
-->
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
-->
<!-- LocalWords: sizeof PairGen pre Siek htm AdaptableUnaryFunction
-->
<!-- LocalWords: ConstBaseIterator
-->

View File

@@ -0,0 +1,96 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
#include <boost/config.hpp>
#include <list>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <boost/iterator_adaptors.hpp>
struct personnel_record {
personnel_record(std::string n, int id) : m_name(n), m_ID(id) { }
std::string m_name;
int m_ID;
};
struct select_name {
typedef personnel_record argument_type;
typedef std::string result_type;
const std::string& operator()(const personnel_record& r) const {
return r.m_name;
}
std::string& operator()(personnel_record& r) const {
return r.m_name;
}
};
struct select_ID {
typedef personnel_record argument_type;
typedef int result_type;
const int& operator()(const personnel_record& r) const {
return r.m_ID;
}
int& operator()(personnel_record& r) const {
return r.m_ID;
}
};
int main(int, char*[])
{
std::list<personnel_record> personnel_list;
personnel_list.push_back(personnel_record("Barney", 13423));
personnel_list.push_back(personnel_record("Fred", 12343));
personnel_list.push_back(personnel_record("Wilma", 62454));
personnel_list.push_back(personnel_record("Betty", 20490));
// Example of using projection_iterator_generator
// to print out the names in the personnel list.
boost::projection_iterator_generator<select_name,
std::list<personnel_record>::iterator>::type
personnel_first(personnel_list.begin()),
personnel_last(personnel_list.end());
std::copy(personnel_first, personnel_last,
std::ostream_iterator<std::string>(std::cout, "\n"));
std::cout << std::endl;
// Example of using projection_iterator_pair_generator
// to assign new ID numbers to the personnel.
typedef boost::projection_iterator_pair_generator<select_ID,
std::list<personnel_record>::iterator,
std::list<personnel_record>::const_iterator> PairGen;
PairGen::iterator ID_first(personnel_list.begin()),
ID_last(personnel_list.end());
int new_id = 0;
while (ID_first != ID_last) {
*ID_first = new_id++;
++ID_first;
}
PairGen::const_iterator const_ID_first(personnel_list.begin()),
const_ID_last(personnel_list.end());
std::copy(const_ID_first, const_ID_last,
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
std::cout << std::endl;
// Example of using make_const_projection_iterator()
// to print out the names in the personnel list again.
std::copy
(boost::make_const_projection_iterator<select_name>(personnel_list.begin()),
boost::make_const_projection_iterator<select_name>(personnel_list.end()),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}

331
reverse_iterator.htm Normal file
View File

@@ -0,0 +1,331 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Reverse Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"center" width="277" height="86">
<h1>Reverse Iterator Adaptor</h1>
Defined in header <a href=
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>The reverse iterator adaptor flips the direction of a base iterator's
motion. Invoking <tt>operator++()</tt> moves the base iterator backward and
invoking <tt>operator--()</tt> moves the base iterator forward. The Boost
reverse iterator adaptor is better to use than the
<tt>std::reverse_iterator</tt> class in situations where pairs of
mutable/constant iterators are needed (e.g., in containers) because
comparisons and conversions between the mutable and const versions are
implemented correctly.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
class Value, class Reference, class Pointer, class Category, class Distance&gt;
struct reverse_iterator_generator;
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>&gt;
typename reverse_iterator_generator&lt;BidirectionalIterator&gt;::type
make_reverse_iterator(BidirectionalIterator base)
}
</pre>
<hr>
<h2><a name="reverse_iterator_generator">The Reverse Iterator Type
Generator</a></h2>
The <tt>reverse_iterator_generator</tt> template is a <a href=
"../../more/generic_programming.html#type_generator">generator</a> of
reverse iterator types. The main template parameter for this class is the
base <tt>BidirectionalIterator</tt> type that is being adapted. In most
cases the associated types of the base iterator can be deduced using
<tt>std::iterator_traits</tt>, but in some situations the user may want to
override these types, so there are also template parameters for the base
iterator's associated types.
<blockquote>
<pre>
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
class Value, class Reference, class Pointer, class Category, class Distance&gt;
class reverse_iterator_generator
{
public:
typedef <tt><a href=
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt;</tt> type; // the resulting reverse iterator type
};
</pre>
</blockquote>
<h3>Example</h3>
In this example we sort a sequence of letters and then output the sequence
in descending order using reverse iterators.
<blockquote>
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
int main(int, char*[])
{
char letters[] = "hello world!";
const int N = sizeof(letters)/sizeof(char) - 1;
std::cout &lt;&lt; "original sequence of letters:\t"
&lt;&lt; letters &lt;&lt; std::endl;
std::sort(letters, letters + N);
// Use reverse_iterator_generator to print a sequence
// of letters in reverse order.
boost::reverse_iterator_generator&lt;char*&gt;::type
reverse_letters_first(letters + N),
reverse_letters_last(letters);
std::cout &lt;&lt; "letters in descending order:\t";
std::copy(reverse_letters_first, reverse_letters_last,
std::ostream_iterator&lt;char&gt;(std::cout));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
</blockquote>
The output is:
<blockquote>
<pre>
original sequence of letters: hello world!
letters in descending order: wroolllhed!
</pre>
</blockquote>
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt><a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a></tt>
<td>The iterator type being wrapped.
<tr>
<td><tt>Value</tt>
<td>The value-type of the base iterator and the resulting reverse
iterator.<br>
<b>Default:</b><tt>std::iterator_traits&lt;BidirectionalIterator&gt;::value_type</tt>
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&amp;</tt> is
used. Otherwise
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::reference</tt>
is used.
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::pointer</tt>.
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::iterator_category</tt>
<tr>
<td><tt>Distance</tt>
<td>The <tt>difference_type</tt> for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BidirectionalIterator&amp;gt::difference_type</tt>
</table>
<h3>Concept Model</h3>
The indirect iterator will model whichever <a href=
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator concept
category</a> is modeled by the base iterator. Thus, if the base iterator is
a model of <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> then so is the resulting indirect iterator. If the base
iterator models a more restrictive concept, the resulting indirect iterator
will model the same concept. The base iterator must be at least a <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional
Iterator</a>
<h3>Members</h3>
The reverse iterator type implements the member functions and operators
required of the <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> concept. In addition it has the following constructor:
<blockquote>
<pre>
reverse_iterator_generator::type(const BidirectionalIterator&amp; it)
</pre>
</blockquote>
<br>
<br>
<hr>
<p>
<h2><a name="make_reverse_iterator">The Reverse Iterator Object
Generator</a></h2>
The <tt>make_reverse_iterator()</tt> function provides a more convenient
way to create reverse iterator objects. The function saves the user the
trouble of explicitly writing out the iterator types.
<blockquote>
<pre>
template &lt;class BidirectionalIterator&gt;
typename reverse_iterator_generator&lt;BidirectionalIterator&gt;::type
make_reverse_iterator(BidirectionalIterator base);
</pre>
</blockquote>
<h3>Example</h3>
In this part of the example we use <tt>make_reverse_iterator()</tt> to
print the sequence of letters in reverse-reverse order, which is the
original order.
<blockquote>
<pre>
// continuing from the previous example...
std::cout &lt;&lt; "letters in ascending order:\t";
std::copy(boost::make_reverse_iterator(reverse_letters_last),
boost::make_reverse_iterator(reverse_letters_first),
std::ostream_iterator&lt;char&gt;(std::cout));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
</blockquote>
The output is:
<blockquote>
<pre>
letters in ascending order: !dehllloorw
</pre>
</blockquote>
<hr>
<h2><a name="interactions">Constant/Mutable Iterator Interactions</a></h2>
<p>One failing of the standard <tt><a
href="http://www.sgi.com/tech/stl/ReverseIterator.html">reverse_iterator</a></tt>
adaptor is that it doesn't properly support interactions between adapted
<tt>const</tt> and non-<tt>const</tt> iterators. For example:
<blockquote>
<pre>
#include &lt;vector&gt;
template &lt;class T&gt; void convert(T x) {}
// Test interactions of a matched pair of random access iterators
template &lt;class Iterator, class ConstIterator&gt;
void test_interactions(Iterator i, ConstIterator ci)
{
bool eq = i == ci; // comparisons
bool ne = i != ci;
bool lt = i &lt; ci;
bool le = i &lt;= ci;
bool gt = i &gt; ci;
bool ge = i &gt;= ci;
std::size_t distance = i - ci; // difference
ci = i; // assignment
ConstIterator ci2(i); // construction
convert&lt;ConstIterator&gt;(i); // implicit conversion
}
void f()
{
typedef std::vector&lt;int&gt; vec;
vec v;
const vec&amp; cv;
test_interactions(v.begin(), cv.begin()); // <font color="#007F00">OK</font>
test_interactions(v.rbegin(), cv.rbegin()); // <font color="#FF0000">ERRORS ON EVERY TEST!!</font>
</pre>
</blockquote>
Reverse iterators created with <tt>boost::reverse_iterator_generator</tt> don't have this problem, though:
<blockquote>
<pre>
typedef boost::reverse_iterator_generator&lt;vec::iterator&gt;::type ri;
typedef boost::reverse_iterator_generator&lt;vec::const_iterator&gt;::type cri;
test_interactions(ri(v.begin()), cri(cv.begin())); // <font color="#007F00">OK!!</font>
</pre>
</blockquote>
Or, more simply,
<blockquote>
<pre>
test_interactions(
boost::make_reverse_iterator(v.begin()),
boost::make_reverse_iterator(cv.begin())); // <font color="#007F00">OK!!</font>
}
</pre>
</blockquote>
<p>If you are wondering why there is no
<tt>reverse_iterator_pair_generator</tt> in the manner of <tt><a
href="projection_iterator.htm#projection_iterator_pair_generator">projection_iterator_pair_generator</a></tt>,
the answer is simple: we tried it, but found that in practice it took
<i>more</i> typing to use <tt>reverse_iterator_pair_generator</tt> than to
simply use <tt>reverse_iterator_generator</tt> twice!<br><br>
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
<p>&copy; Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell
and distribute this document is granted provided this copyright notice
appears in all copies. This document is provided "as is" without express or
implied warranty, and with no claim as to its suitability for any purpose.
<!-- LocalWords: html charset alt gif hpp BidirectionalIterator const namespace struct
-->
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
-->
<!-- LocalWords: sizeof PairGen pre Siek wroolllhed dehllloorw
-->
</body>
</html>

View File

@@ -0,0 +1,42 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/iterator_adaptors.hpp>
int main(int, char*[])
{
char letters[] = "hello world!";
const int N = sizeof(letters)/sizeof(char) - 1;
std::cout << "original sequence of letters:\t"
<< letters << std::endl;
std::sort(letters, letters + N);
// Use reverse_iterator_generator to print a sequence
// of letters in reverse order.
boost::reverse_iterator_generator<char*>::type
reverse_letters_first(letters + N),
reverse_letters_last(letters);
std::cout << "letters in descending order:\t";
std::copy(reverse_letters_first, reverse_letters_last,
std::ostream_iterator<char>(std::cout));
std::cout << std::endl;
// Use make_reverse_iterator() to print the sequence
// of letters in reverse-reverse order.
std::cout << "letters in ascending order:\t";
std::copy(boost::make_reverse_iterator(reverse_letters_last),
boost::make_reverse_iterator(reverse_letters_first),
std::ostream_iterator<char>(std::cout));
std::cout << std::endl;
return 0;
}

137
tie.html Normal file
View File

@@ -0,0 +1,137 @@
<HTML>
<!--
-- Copyright (c) Jeremy Siek, Lie-Quan Lee, and Andrew Lumsdaine 2000
--
-- Permission to use, copy, modify, distribute and sell this software
-- and its documentation for any purpose is hereby granted without fee,
-- provided that the above copyright notice appears in all copies and
-- that both that copyright notice and this permission notice appear
-- in supporting documentation. We make no
-- representations about the suitability of this software for any
-- purpose. It is provided "as is" without express or implied warranty.
-->
<Head>
<Title>Boost Tie</Title>
<BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
ALINK="#ff0000">
<IMG SRC="../../c++boost.gif"
ALT="C++ Boost" width="277" height="86">
<BR Clear>
<H1><A NAME="sec:tie"></A>
<TT>tie</TT>
</H1>
<P>
<PRE>
template &lt;class A, class B&gt;
tied&lt;A,B&gt; tie(A&amp; a, B&amp; b);
</PRE>
<P>
This is a utility function that makes it more convenient to work with
a function which returns a std::pair&lt;&gt;. 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&#228;rvi's Binders&nbsp;[<A
HREF="../graph/doc/bibliography.html#jaakko_tuple_assign">1</A>].
<P>
<H3>Where Defined</H3>
<P>
<a href="../../boost/utility.hpp"><TT>boost/utility.hpp</TT></a>
<P>
<H3>Example</H3>
<P>
An example of using the <TT>tie()</TT> function with the
<TT>vertices()</TT> function, which returns a pair of
type <TT>std::pair&lt;vertex_iterator,vertex_iterator&gt;</TT>. The
pair of iterators is assigned to the iterator variables <TT>i</TT> and
<TT>end</TT>.
<P>
<PRE>
graph_traits&lt; adjacency_list&lt;&gt; &gt;::vertex_iterator i, end;
for(tie(i,end) = vertices(G); i != end; ++i)
// ...
</PRE>
<P>
Here is another example that uses <TT>tie()</TT> for handling operations with <a
href="http://www.sgi.com/tech/stl/set.html"><TT>std::set</TT></a>.
<P>
<PRE>
#include &lt;set&gt;
#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;boost/utility.hpp&gt;
int
main(int, char*[])
{
{
typedef std::set&lt;int&gt; 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&lt;iterator,bool&gt;
int new_vals[2] = { 3, 9 };
for (int k = 0; k &lt; 2; ++k) {
boost::tie(i,inserted) = s.insert(new_vals[k]);
if (!inserted)
std::cout &lt;&lt; *i &lt;&lt; &quot; was already in the set.&quot; &lt;&lt; std::endl;
else
std::cout &lt;&lt; *i &lt;&lt; &quot; successfully inserted.&quot; &lt;&lt; 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&lt;iterator,iterator&gt;
boost::tie(i,end) = std::equal_range(vals, vals + 6, 4);
std::cout &lt;&lt; &quot;There were &quot; &lt;&lt; std::distance(i,end)
&lt;&lt; &quot; occurrences of &quot; &lt;&lt; *i &lt;&lt; &quot;.&quot; &lt;&lt; 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 &copy 2000</TD><TD>
<A HREF=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>,
Univ.of Notre Dame (<A
HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)<br>
<A HREF=http://www.lsc.nd.edu/~llee1>Lie-Quan Lee</A>, Univ.of Notre Dame (<A HREF="mailto:llee1@lsc.nd.edu">llee1@lsc.nd.edu</A>)<br>
<A HREF=http://www.lsc.nd.edu/~lums>Andrew Lumsdaine</A>,
Univ.of Notre Dame (<A
HREF="mailto:lums@lsc.nd.edu">lums@lsc.nd.edu</A>)
</TD></TR></TABLE>
</BODY>
</HTML>

61
tie_example.cpp Normal file
View File

@@ -0,0 +1,61 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
//
// This is an example demonstrating how to use the tie() function.
// The purpose of tie() is to make it easiery to deal with std::pair
// return values.
//
// Contributed by Jeremy Siek
//
// Sample output
//
// 3 successfully inserted.
// 9 was already in the set.
// There were 2 occurances of 4.
#include <set>
#include <algorithm>
#include <iostream>
#include <boost/utility.hpp>
int
main(int, char*[])
{
{
typedef std::set<int> SetT;
SetT::iterator i, end;
bool inserted;
int vals[5] = { 5, 2, 4, 9, 1 };
SetT s(vals, vals + 5);
// Using tie() with a return value of pair<iterator,bool>
int new_vals[2] = { 3, 9 };
for (int k = 0; k < 2; ++k) {
boost::tie(i,inserted) = s.insert(new_vals[k]);
if (!inserted)
std::cout << *i << " was already in the set." << std::endl;
else
std::cout << *i << " successfully inserted." << std::endl;
}
}
{
int* i, *end;
int vals[6] = { 5, 2, 4, 4, 9, 1 };
std::sort(vals, vals + 6);
// Using tie() with a return value of pair<iterator,iterator>
boost::tie(i,end) = std::equal_range(vals, vals + 6, 4);
std::cout << "There were " << std::distance(i,end)
<< " occurances of " << *i << "." << std::endl;
// Footnote: of course one would normally just use std::count()
// to get this information, but that would spoil the example :)
}
return 0;
}

75
tmpw2001-paper/Makefile Normal file
View File

@@ -0,0 +1,75 @@
# -*- makefile -*-
DVIPS = dvips
LATEX = pdflatex
LATEXOUT = pdf
RESULT = pdf
#LATEX = latex
#LATEXOUT = dvi
#RESULT = ps
.SUFFIXES: .tex .dvi .ps .pdf .c .lg .eps
.c.lg:
lgrind -i -o $*.lg -a -lc++ $*.c
.eps.pdf:
epstopdf $*.eps
.tex.pdf:
@ if test ! -f $*.ind; then echo "" > $*.ind; fi
@ $(LATEX) $*
@ if ( grep 'Writing index file' $*.log > /dev/null ); \
then makeindex $* ; $(LATEX) $* ; fi
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
then $(LATEX) $* ; fi
@ if ( grep 'LaTeX Warning: Citation' $*.log > /dev/null ); \
then bibtex $* ; $(LATEX) $* ; fi
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
then $(LATEX) $* ; fi
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
then $(LATEX) $* ; fi
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
then $(LATEX) $* ; fi
.dvi.ps:
$(DVIPS) -o $*.ps $*
.ps.pdf:
distill -v -maxsubsetpct 99 -subsetfonts on -pairs $*.ps $*.pdf
SRCCODE =
#
# Default rule
#
default: iter-adaptor.$(RESULT)
#
# LaTeX stuff
#
TEX = iter-adaptor.tex
iter-adaptor.dvi: $(TEX) $(SRCCODELG)
iter-adaptor.ps: iter-adaptor.dvi
iter-adaptor.pdf: $(PDFPICT) $(TEX) $(SRCCODELG)
dist: iter-adaptor.ps iter-adaptor.pdf
mkdir -p iter-adaptor
cp $(TEX) $(SRCCODELG) $(EPS) $(PS) \
iter-adaptor.bbl iter-adaptor.ps iter-adaptor.pdf \
iter-adaptor
tar cvf - ./iter-adaptor | gzip > iter-adaptor.tar.gz
#
# Standard rules
#
clean:
/bin/rm -f *.dvi *.o *.ps *.pdf *.log *.blg *.bbl *.aux *~ *.out *.ind

36
tmpw2001-paper/defs.tex Normal file
View File

@@ -0,0 +1,36 @@
\usepackage{times}
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse
\else
\pdfoutput=1
\pdftrue
\fi
\ifpdf
\usepackage[
pdftex,
colorlinks=true,
linkcolor=blue,filecolor=blue,pagecolor=blue,urlcolor=blue
]{hyperref}
\fi
\ifpdf
\newcommand{\concept}[1]{\hyperref[concept:#1]{\textsf{#1}}}
\newcommand{\stlconcept}[1]{\href{http://www.sgi.com/tech/stl/#1.html}{\textsf{#1}}}
\newcommand{\link}[2]{\hyperref[#1]{#2}}
\else
\newcommand{\concept}[1]{\textsf{#1}}
\newcommand{\stlconcept}[1]{\textsf{#1}}
\newcommand{\href}[2]{#2}
\newcommand{\link}[2]{#2}
\fi
\newcommand{\code}[1]{{\small \texttt{#1}}}
\newcommand{\Note}[1]{\marginpar{\begin{flushleft}%
{%%\tiny %%\footnotesize
{\bf Note:} #1}%
\end{flushleft}}}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
% Paper Formatting according to requirements of Net.Objectdays 2000
\LoadClass[10pt]{article}
\pagestyle{empty}
% ---------------------------------------------------------------------
\textheight193mm
\textwidth122mm
\oddsidemargin44mm
\hoffset-1in \voffset-1in
\topmargin52mm
\headsep0pt
\headheight0pt
% ---------------------------------------------------------------------
\renewcommand\maketitle{\par
\begingroup
\renewcommand\thefootnote{\@fnsymbol\c@footnote}%
\def\@makefnmark{\rlap{\@textsuperscript{\normalfont\@thefnmark}}}%
\long\def\@makefntext##1{\parindent 1em\noindent
\hb@xt@1.8em{%
\hss\@textsuperscript{\normalfont\@thefnmark}}##1}%
\if@twocolumn
\ifnum \col@number=\@ne
\@maketitle
\else
\twocolumn[\@maketitle]%
\fi
\else
\newpage
\global\@topnum\z@ % Prevents figures from going at top of page.
\@maketitle
\fi
\thispagestyle{empty}\@thanks
\endgroup
\setcounter{footnote}{0}%
\global\let\thanks\relax
\global\let\maketitle\relax
\global\let\@maketitle\relax
\global\let\@thanks\@empty
\global\let\@author\@empty
\global\let\@date\@empty
\global\let\@title\@empty
\global\let\title\relax
\global\let\author\relax
\global\let\date\relax
\global\let\and\relax
}
\date{}
\def\@maketitle{%
\newpage
\null
\vskip 2em%
\begin{center}%
\let \footnote \thanks
{\Large \textbf{\@title} \par}%
\vskip 1.5em%
{\large
\lineskip .5em%
{\normalsize
\begin{tabular}[t]{c}%
\@author
\end{tabular}\par}}%
\vskip 1em%
{\large \@date}%
\end{center}%
\par
\vskip 1.5em}
\renewcommand\section{\@startsection {section}{1}{\z@}%
{-3.5ex \@plus -1ex \@minus -.2ex}%
{2.3ex \@plus.2ex}%
{\normalfont\large\bfseries}}
\renewcommand\subsection{\@startsection{subsection}{2}{\z@}%
{-3.25ex\@plus -1ex \@minus -.2ex}%
{1.5ex \@plus .2ex}%
{\normalfont\normalsize\bfseries}}
\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%
{-3.25ex\@plus -1ex \@minus -.2ex}%
{1.5ex \@plus .2ex}%
{\normalfont\normalsize\bfseries}}
\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}%
{3.25ex \@plus1ex \@minus.2ex}%
{-1em}%
{\normalfont\normalsize\bfseries}}
\renewcommand\subparagraph{\@startsection{subparagraph}{5}{\parindent}%
{3.25ex \@plus1ex \@minus .2ex}%
{-1em}%
{\normalfont\normalsize\bfseries}}
\renewcommand{\figurename}{Fig}
\renewcommand{\tablename}{Tab}
\long\def\@makecaption#1#2{%
\vskip\abovecaptionskip
\sbox\@tempboxa{{\small\textbf{#1.} #2}}%
\ifdim \wd\@tempboxa >\hsize
{\small\textbf{#1.} #2}\par
\else
\global \@minipagefalse
\hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
\fi
\vskip\belowcaptionskip}
\renewenvironment{abstract}
{\list{}{\leftmargin1cm\rightmargin\leftmargin}%
\item\relax{\small \textbf{Abstract.}}}
{\endlist}

124
tmpw2001-paper/refs.bib Normal file
View File

@@ -0,0 +1,124 @@
@TechReport{stepa.lee-1994:the.s:TR,
author = "A. A. Stepanov and M. Lee",
title = "{The Standard Template Library}",
institution = "ISO Programming Language C++ Project",
year = "1994",
number = "X3J16/94-0095, WG21/N0482",
month = may,
}
@Book{ austern99:_gener_progr_stl,
author = "Matthew H. Austern",
title = "Generic Programming and the {STL}",
publisher = "Addison-Wesley",
year = 1999,
series = "Professional computing series"
}
@Book{koenig97:_rumin_cpp,
author = {Andrew Koenig and Barbara Moo},
title = {Ruminations on {C++}},
publisher = {Addison Wesley},
year = 1997
}
@Book{iso98:_cpp_final_draft_standard,
author = "International Organization for Standardization
(ISO)",
title = "ISO/IEC Final Draft International Standard 14882:
Programming Language C++",
year = 1998,
address = "1 rue de Varemb\'e, Case postale 56, CH-1211
Gen\`eve 20, Switzerland"
}
@Book{alexandrescu01:_modern_cpp_design,
author = {Andrei Alexandrescu},
title = {Modern {C++} Design},
publisher = {Addison Wesley},
year = 2001
}
@BOOK { Barton94,
AUTHOR = "John Barton and Lee Nackman",
TITLE = "Scientific and Engineering {C++}",
PUBLISHER = "Addison-Wesley",
YEAR = 1994
}
@Book{gamma95:_design_patterns,
author = {Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides},
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
publisher = {Addison-Welsey},
year = 1995,
series = {Professional Computing}
}
@Book{stroustrup00:_cpp_prog_lang,
author = {Bjarne Stroustrup},
title = {The {C++} Programming Language},
publisher = {Addison-Wesley},
year = 2000,
edition = {Special}
}
@Article{alexandrescu98:_compound_iters,
author = {Andrei Alexandrescu},
title = {Compound iterators of {STL}},
journal = {{C/C++} Users Journal},
year = 1998,
volume = 16,
number = 10,
pages = {79-82},
month = October
}
@Article{becker98:_smart_iteraters,
author = {Thomas Becker},
title = {Smart Iterators and STL},
journal = {{C/C++} Users Journal},
year = 1998,
volume = 16,
number = 9,
month = {September}
}
@InBook{siek99:_scitools,
author = {Jeremy G. Siek and Andrew Lumsdaine},
title = {Modern Software Tools for Scientific Computing},
chapter = {A Modern Framework for Portable High Performance
Numerical Linear Algebra},
publisher = {Birkhauser},
year = 1999,
}
@TechReport{siek01:_improved_iter_cat,
author = {Jeremy Siek},
title = {Improved Iterator Categories and Requirements},
institution = {ISO IEC JTC1/SC22/WG21 - C++},
year = 2001,
number = {N1297}
}
@Book{mehlhorn99:_leda,
author = {K. Mehlhorn and St. N\"aher},
title = {The LEDA Platform of Combinatorial and Geometric Computing},
publisher = {Cambridge University Press},
year = 1999
}
@Book{ knu94:sgb,
author = {D. E. Knuth},
title = {Stanford GraphBase: a platform for combinatorial computing},
publisher = {ACM Press},
year = {1994}
}
@Misc{czarnecki00:_named_param,
author = {Krzysztof Czarnecki and Ulrich Eisenecker},
title = {Named Parameters for Configuration Generators},
howpublished = {http://www.generative-programming.org/namedparams/},
year = 2000
}

249
tmpw2001-paper/tmpw00.bib Normal file
View File

@@ -0,0 +1,249 @@
@InProceedings{TMPW00:Eisenecker,
AUTHOR = "Ulrich W. Eisenecker and Frank Blinn and Krzysztof Czarnecki",
TITLE = "A Solution to the Constructor-Problem of Mixin-Based Programming in {C++}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"Mixin-Based Programming in C++ is a powerful programming style
based on the parameterized inheritance idiom and the composition
of C++ templates. Type expressions describing specific inheritance
hierarchies can be composed either automatically using generative
programming idioms in C++ or manually. Unfortunately, the mixin-based
C++ programming techniques published to date do not adequately support
optional and alternative mixin classes with constructors expecting
varying numbers of arguments, which are common in practice. This
is because the varying base class constructors do not provide a
uniform interface on which the constructors of the derived classes
could rely. This paper discusses several partial solutions to this
problem that were proposed to date and presents a new, complete
solution. The new solution uses generative programming techniques to
automatically generate the appropriate constructors, and this way it
avoids the overhead and clumsiness of instantiating composed mixin
classes in the client code using the partial solutions. In fact,
the new solution allows users to instantiate automatically composed
mixin classes with the simplicity of instantiating concrete classes
from traditional class hierarchies. Finally, the new solution does
not suffer from the scalability problems of the partial solutions."
}
@InProceedings{TMPW00:Berti,
AUTHOR = "Guntram Berti",
TITLE = "Generic Components for Grid Data Structures and Algorithms with {C++}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"Grids are fundamental data structures for representing
geometric structures or their subdivisions. We propose a strategy
for decoupling algorithms working on grids from the details of
grid representations, using a generic programming approach in C++.
Functionality of grid data structures is captured by a small set of
primitives, divided into combinatorial and geometric ones. Special
attention is paid to the generic implementation of grid functions, which
correspond to the notion of mappings from grid elements (e. g. vertices)
to entities of a given type. Experiments indicate that the overhead
of the generic formulation is low and can be completely eliminated in
some cases."
}
@InProceedings{TMPW00:Veldhuizen,
AUTHOR = "Todd L. Veldhuizen",
TITLE = "Five compilation models for {C++} templates",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"This paper proposes an alternate structure for C++ compilers.
Type analysis is removed from the compiler and replaced with a
`type system library' which is treated as source code by the
compiler. Type computations are embedded in the intermediate
language of the compiler, and partial evaluation is used to drive
type analysis and template instantiation. By making simple changes to
the behavior of the partial evaluator, a wide range of compilation
models is achieved, each with a distinct tradeoff of compile time, code
size, and code speed. These models range from pure dynamic typing --
ideal for scripting C++ -- to profile-directed template instantiation.
This approach may solve several serious problems in compiling C++:
it achieves separate compilation of templates, allows template
code to be distributed in binary form by deferring template instantiation
until run time, and reduces the code bloat associated with
templates."
}
@InProceedings{TMPW00:Baus,
AUTHOR = "Christopher Baus and Thomas Becker",
TITLE = "Custom Iterators for the {STL}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"We discuss several kinds of custom iterators for use with the STL
that are substantially different from the iterators that come with
the STL. We present class templates that implement these custom
iterators in a generic manner."
}
@InProceedings{TMPW00:Weiser,
AUTHOR = "Martin Weiser and Gary Powell",
TITLE = "The {View Template Library}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"Views are container adaptors providing access to different
on the fly generated representations of the data in the container they
are applied to. The concept fits nicely into the framework defined by
the STL. This paper explains design, usage, and implementation of the
View Template Library, the currently most advanced implementation of
the views concept."
}
@InProceedings{TMPW00:Striegnitz,
AUTHOR = "J{\"o}rg Striegnitz and Stephen A. Smith",
TITLE = "An Expression Template aware Lambda Function",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"Template libraries such as the STL contain several generic algorithms
that expect functions as arguments and thereby cause frequent use of
function objects. User-defined function objects are awkward because
they must be declared as a class in namespace scope before they may
be used. In this paper, we describe a lambda function for C++, which
allows users to define function objects on the fly, without writing class
declarations. We show that, by using expression templates, the lambda
function can be implemented without hurting the runtime performance of a
program. Expression templates can also help to overcome the performance
penalties that may arise when using expressions over user-defined
types. Thus, we based our approach on PETE which is a framework
that simplifies the addition of expression template functionality to
user-defined classes."
}
@InProceedings{TMPW00:McNamara,
AUTHOR = "Brian McNamara and Yannis Smaragdakis",
TITLE = "Static Interfaces in {C++}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"We present an extensible framework for defining and
using ``static interfaces'' in C++. Static interfaces are especially
useful as constraints on template parameters. That is, in addition to the
usual template $class T$, template definitions can specify that T ``isa''
Foo, for some static interface named Foo. These ``isa-constraints'' can be
based on either inheritance (named conformance: T publicly inherits Foo),
members (structural conformance: T has these member functions with these
signatures), or both. The constraint mechanism imposes no space or time
overheads at runtime; virtual functions are conspicuously absent from
our framework.
We demonstrate two key utilities of static interfaces. First,
constraints enable better error messages with template code. By applying
static interfaces as constraints, instantiating a template with the
wrong type is an error that can be caught at the instantiation point,
rather than later (typically in the bowels of the implementation).
Authors of template classes and template functions can also dispatch
``custom error messages'' to report named constraint violations by
clients, making debugging easier. We show examples of the improvement of
error messages when constraints are applied to STL code.
Second, constraints enable automatic compile-time dispatch of different
implementations of class or function templates based on the named
conformance properties of the template types. For example, $Set<T>$ can be
written to automatically choose the most efficient implementation: use a
hashtable implementation if ``T isa Hashable'', or else a binary search
tree if ``T isa LessThanComparable'' , or else a linked-list if merely ``T
isa EqualityComparable''. This dispatch can be completely hidden from
clients of Set, who just use $Set<T>$ as usual."
}
@InProceedings{TMPW00:Siek,
AUTHOR = "Jeremy Siek and Andrew Lumsdaine",
TITLE = "Concept Checking: Binding Parametric Polymorphism in {C++}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"Generic programming in C++ is characterized by the use of template
parameters to represent abstract data types (or ``concepts'').
However, the C++ language itself does not provide a mechanism for
explicitly handling concepts. As a result, it can be difficult to
insure that a concrete type meets the requirements of the concept it
is supposed to represent. Error messages resulting from incorrect
use of a concrete type can be particularly difficult to decipher.
In this paper we present techniques to check parameters in generic
C++ libraries. Our techniques use standard C++ and introduce no
run-time overhead."
}
@InProceedings{TMPW00:Kuehl,
AUTHOR = "Dietmar K{\"u}hl",
TITLE = "{STL} and {OO} Don't Easily Mix",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/",
ABSTRACT =
"The STL is a powerful tool for many kinds of processing. Unfortunately,
using polymorphic objects with the STL seems not to work: Polymorphic
objects stored in STL containers either get sliced (i.e. only the base
part is copied or assigned but not the derived part) or, when storing
pointers to them instead, are not destroyed. Applying algorithms to
such containers often results in the wrong thing or complex predicate
objects are needed. This article shows how to overcome at least some
of these problems using some adaptors and also outlines a possible
implementation of STL for better integration with polymorphic objects.
The improved integration just acknowledges the distinction between the
object and the entity used to maintain it."
}
@InProceedings{TMPW00:Eichelberger,
AUTHOR = "H. Eichelberger and J. Wolff v. Gudenberg",
TITLE = "{UML} Description of the {STL}",
BOOKTITLE = "First Workshop on {C++} Template Programming,
Erfurt, Germany",
MONTH = "October 10",
YEAR = "2000",
URL = "http://oonumerics.org/tmpw00/eichelberger.pdf",
ABSTRACT =
"In this paper we show how the specification of the
Standard Template Library STL and its implementation can be described
by UML diagrams. We define appropriate stereotypes to
describe STL concepts like containers, iterators, function
objects and global algorithms. For the graphical description of the
implementation of the STL we extend the UML metamodel."
}

223
transform_iterator.htm Normal file
View File

@@ -0,0 +1,223 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Transform Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Transform Iterator Adaptor</h1>
Defined in header
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>
The transform iterator adaptor augments an iterator by applying some
function object to the result of dereferencing the iterator. Another
words, the <tt>operator*</tt> of the transform iterator first
dereferences the base iterator, passes the result of this to the
function object, and then returns the result. The following
<b>pseudo-code</b> shows the basic idea:
<pre>
value_type transform_iterator::operator*() const {
return this->f(*this->base_iterator);
}
</pre>
All of the other operators of the transform iterator behave in the
same fashion as those of the base iterator.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
class transform_iterator_generator;
template &lt;class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator&gt;
typename transform_iterator_generator&lt;AdaptableUnaryFunction,Iterator&gt;::type
make_transform_iterator(BaseIterator base, const AdaptableUnaryFunction&amp; f = AdaptableUnaryFunction());
}
</pre>
<hr>
<h2><a name="transform_iterator_generator">The Transform Iterator Type
Generator</a></h2>
The class <tt>transform_iterator_generator</tt> is a helper class whose
purpose is to construct a transform iterator type. The template
parameters for this class are the <tt>AdaptableUnaryFunction</tt> function object
type and the <tt>BaseIterator</tt> type that is being wrapped.
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator&gt;
class transform_iterator_generator
{
public:
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt; type;
};
</pre>
<h3>Example</h3>
<p>
The following is an example of how to use the
<tt>transform_iterator_generator</tt> class to iterate through a range
of numbers, multiplying each of them by 2 when they are dereferenced.
The <tt>boost::binder1st</tt> class is used instead of the standard
one because tranform iterator requires the function object to be
Default Constructible.
<p>
<PRE>
#include &lt;functional&gt;
#include &lt;iostream&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
// definition of class boost::binder1st and function boost::bind1st() ...
int
main(int, char*[])
{
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
typedef boost::binder1st&lt; std::multiplies&lt;int&gt; &gt; Function;
typedef boost::transform_iterator_generator&lt;Function, int*&gt;::type doubling_iterator;
doubling_iterator i(x, boost::bind1st(std::multiplies&lt;int&gt;(), 2)),
i_end(x + sizeof(x)/sizeof(int), boost::bind1st(std::multiplies&lt;int&gt;(), 2));
std::cout &lt;&lt; "multiplying the array by 2:" &lt;&lt; std::endl;
while (i != i_end)
std::cout &lt;&lt; *i++ &lt;&lt; " ";
std::cout &lt;&lt; std::endl;
// to be continued...
</PRE>
The output from this part is:
<pre>
2 4 6 8 10 12 14 16
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><a
href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
<TD>The function object that transforms each element in the iterator
range. The <tt>argument_type</tt> of the function object must match
the value type of the base iterator. The <tt>result_type</tt> of the
function object will be the resulting iterator's
<tt>value_type</tt>. If you want the resulting iterator to behave as
an iterator, the result of the function should be solely a function of
its argument. Also, the function object must be <a
href="http://www.sgi.com/tech/stl/DefaultConstructible.html"> Default
Constructible</a> (which many of the standard function objects are not).</TD>
</TR>
<TR>
<TD><tt>BaseIterator</tt></TD>
<TD>The iterator type being wrapped. This type must at least be a model
of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD>
</TR>
</Table>
<h3>Model of</h3>
The transform iterator adaptor (the type
<tt>transform_iterator_generator<...>::type</tt>) is a model of <a
href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a><a href="#1">[1]</a>.
<h3>Members</h3>
The transform iterator type implements the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a>
concept, except that the <tt>reference</tt> type is the same as the <tt>value_type</tt>
so <tt>operator*()</tt> returns by-value. In addition it has the following constructor:
<pre>
transform_iterator_generator::type(const BaseIterator&amp; it,
const AdaptableUnaryFunction&amp; f = AdaptableUnaryFunction())
</pre>
<p>
<hr>
<p>
<h2><a name="make_transform_iterator">The Transform Iterator Object Generator</a></h2>
<pre>
template &lt;class AdaptableUnaryFunction, class BaseIterator&gt;
typename transform_iterator_generator&lt;AdaptableUnaryFunction,BaseIterator&gt;::type
make_transform_iterator(BaseIterator base,
const AdaptableUnaryFunction&amp; f = AdaptableUnaryFunction());
</pre>
This function provides a convenient way to create transform iterators.
<h3>Example</h3>
Continuing from the previous example, we use the <tt>make_transform_iterator()</tt>
function to add four to each element of the array.
<pre>
std::cout << "adding 4 to each element in the array:" << std::endl;
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
</pre>
The output from this part is:
<pre>
5 6 7 8 9 10 11 12
</pre>
<h3>Notes</h3>
<a name="1">[1]</a> If the base iterator is a model of <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a>
then the transform iterator will also suppport most of the
functionality required by the Random Access Iterator concept. However, a
transform iterator can never completely satisfy the requirements for
<a
href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward Iterator</a>
(or of any concepts that refine Forward Iterator, which includes
Random Access Iterator and Bidirectional Iterator) since the <tt>operator*</tt> of the transform
iterator always returns by-value.
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->29 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14896" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

View File

@@ -0,0 +1,76 @@
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
#include <functional>
#include <algorithm>
#include <iostream>
#include <boost/iterator_adaptors.hpp>
// What a bummer. We can't use std::binder1st with transform iterator
// because it does not have a default constructor. Here's a version
// that does.
namespace boost {
template <class Operation>
class binder1st
: public std::unary_function<typename Operation::second_argument_type,
typename Operation::result_type> {
protected:
Operation op;
typename Operation::first_argument_type value;
public:
binder1st() { } // this had to be added!
binder1st(const Operation& x,
const typename Operation::first_argument_type& y)
: op(x), value(y) {}
typename Operation::result_type
operator()(const typename Operation::second_argument_type& x) const {
return op(value, x);
}
};
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
typedef typename Operation::first_argument_type arg1_type;
return binder1st<Operation>(op, arg1_type(x));
}
} // namespace boost
int
main(int, char*[])
{
// This is a simple example of using the transform_iterators class to
// generate iterators that multiply the value returned by dereferencing
// the iterator. In this case we are multiplying by 2.
// Would be cooler to use lambda library in this example.
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int N = sizeof(x)/sizeof(int);
typedef boost::binder1st< std::multiplies<int> > Function;
typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator;
doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)),
i_end(x + N, boost::bind1st(std::multiplies<int>(), 2));
std::cout << "multiplying the array by 2:" << std::endl;
while (i != i_end)
std::cout << *i++ << " ";
std::cout << std::endl;
std::cout << "adding 4 to each element in the array:" << std::endl;
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}

View File

@@ -0,0 +1,54 @@
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// Revision History
// 08 Mar 2001 Jeremy Siek
// Moved test of transform iterator into its own file. It to
// to be in iterator_adaptor_test.cpp.
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/iterator_adaptors.hpp>
#include <boost/pending/iterator_tests.hpp>
struct mult_functor {
typedef int result_type;
typedef int argument_type;
// Functors used with transform_iterator must be
// DefaultConstructible, as the transform_iterator must be
// DefaultConstructible to satisfy the requirements for
// TrivialIterator.
mult_functor() { }
mult_functor(int aa) : a(aa) { }
int operator()(int b) const { return a * b; }
int a;
};
int
main()
{
const int N = 10;
// Borland is getting confused about typedef's and constructors here
// Test transform_iterator
{
int x[N], y[N];
for (int k = 0; k < N; ++k)
x[k] = k;
std::copy(x, x + N, y);
for (int k2 = 0; k2 < N; ++k2)
x[k2] = x[k2] * 2;
boost::transform_iterator_generator<mult_functor, int*>::type i(y, mult_functor(2));
boost::input_iterator_test(i, x[0], x[1]);
boost::input_iterator_test(boost::make_transform_iterator(&y[0], mult_functor(2)), x[0], x[1]);
}
std::cout << "test successful " << std::endl;
return 0;
}

View File

@@ -16,10 +16,50 @@
<h2>Contents</h2>
<ul>
<li>Function templates <a href="#checked_delete">checked_delete() and
checked_array_delete()</a></li>
<li>Function templates <a href="#functions next">next() and prior()</a></li>
<li>Class <a href="#Class noncopyable">noncopyable</a></li>
<li>Function template <a href="tie.html">tie()</a> and supporting class tied.</li>
</ul>
<h2> Function templates <a name="checked_delete">checked_delete</a>() and
checked_array_delete()</h2>
<p>Deletion of a pointer to an incomplete type is an unsafe programming practice
because there is no way for the compiler to verify that the destructor is indeed
trivial.&nbsp; The checked_delete() and checked_array_delete() function
templates simply <b>delete</b> or <b>delete[]</b> their argument, but also
require that their argument be a complete type.&nbsp; They issue an appropriate
compiler error diagnostic if that requirement is not met.&nbsp; A typical
implementation is shown; other implementations may vary:</p>
<pre> template&lt; typename T &gt;
inline void checked_delete(T const volatile * x)
{
BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point
// of instantiation
delete x;
}
template&lt; typename T &gt;
inline void checked_array_delete(T const volatile * x)
{
BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point
// of instantiation
delete [] x;
}</pre>
<p>Contributed by Beman Dawes, based on a suggestion from Dave Abrahams,
generalizing an idea from Vladimir Prus, with comments from Rainer Deyke, John
Maddock, and others.</p>
<h3>Background</h3>
<p>The C++ Standard specifies that delete on a pointer to an incomplete types is
undefined behavior if the type has a non-trivial destructor in&nbsp; [expr.delete]
5.3.5 paragraph.&nbsp; No diagnostic is required.&nbsp; Some but not all
compilers issue warnings if the type is incomplete at point of deletion.</p>
<h2> <a name="functions next">Function</a> templates next() and prior()</h2>
<p>Certain data types, such as the C++ Standard Library's forward and
@@ -91,9 +131,11 @@ emphasize that it is to be used only as a base class.&nbsp; Dave Abrahams notes
concern about the effect on compiler optimization of adding (even trivial inline)
destructor declarations. He says &quot;Probably this concern is misplaced, because
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics.&quot;</p>
<h2>Function template tie()</h2>
<p>See <a href="tie.html">separate documentation</a>.</p>
<hr>
<p>Revised&nbsp; <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
-->16 February, 2001<!--webbot bot="Timestamp" endspan i-checksum="40407"
-->22 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13960"
-->
</p>
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and