mirror of
				https://github.com/boostorg/utility.git
				synced 2025-10-31 16:31:48 +01:00 
			
		
		
		
	Compare commits
	
		
			177 Commits
		
	
	
		
			boost-1.20
			...
			svn-branch
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 666f5473d5 | ||
|  | 9a69a25fe8 | ||
|  | 9c3e87fe21 | ||
|  | a9ae944ae4 | ||
|  | 50ba2d419a | ||
|  | ff3a77ca5a | ||
|  | 4eaed6c23d | ||
|  | 4d0dd46471 | ||
|  | 9c2549bd00 | ||
|  | b7c8e0c17f | ||
|  | dd3cfe1837 | ||
|  | 43f525298e | ||
|  | 1bb1898ab9 | ||
|  | 9578f24be9 | ||
|  | 46fae3aed2 | ||
|  | e35f91a70a | ||
|  | 851052fcca | ||
|  | 5ef81b2952 | ||
|  | ef2851c053 | ||
|  | 0b4387cff5 | ||
|  | a40cf11fbf | ||
|  | 5c495cd223 | ||
|  | cf1296dff8 | ||
|  | d6d88db6e8 | ||
|  | 85c2a35257 | ||
|  | 836d8b1c64 | ||
|  | 98d8c8ab71 | ||
|  | db45013339 | ||
|  | a55c37e7f6 | ||
|  | 46a270fcca | ||
|  | 967856518e | ||
|  | 7f93e739fe | ||
|  | 2cd1422514 | ||
|  | feb370b201 | ||
|  | d1b34e64d8 | ||
|  | b9a1eead40 | ||
|  | 1e4bfac98c | ||
|  | 3bb504fbf3 | ||
|  | 5029791c90 | ||
|  | a1a68f0970 | ||
|  | f8543d79eb | ||
|  | f353415136 | ||
|  | 26240403b0 | ||
|  | 3a39729b58 | ||
|  | 096c961d9a | ||
|  | 01fe04a6a2 | ||
|  | 7ea4014993 | ||
|  | d50b374f88 | ||
|  | 27dfb25570 | ||
|  | b5ed77985e | ||
|  | 61243bd15f | ||
|  | 368b94d804 | ||
|  | a5adbbfd5f | ||
|  | a19d13f123 | ||
|  | 78886ab383 | ||
|  | 168012b465 | ||
|  | d9d58ea66e | ||
|  | 56f5f6e8d5 | ||
|  | 3cb6420eda | ||
|  | 60be2c1186 | ||
|  | ed210f6b2c | ||
|  | 029bc59d74 | ||
|  | 961c08a82f | ||
|  | 7ee484c614 | ||
|  | 05c6fbbf99 | ||
|  | 91078b7f7a | ||
|  | 20d804afc4 | ||
|  | c21f6d1cbf | ||
|  | 393e79c1fd | ||
|  | 8b92c8a085 | ||
|  | ff73dd94c9 | ||
|  | af43904f38 | ||
|  | 485074f265 | ||
|  | 2e0ee55b5e | ||
|  | e9105d32cb | ||
|  | 964d23f68c | ||
|  | be5aaaae7b | ||
|  | bf13bd7b3f | ||
|  | 352e392fcb | ||
|  | 083b1b02df | ||
|  | 648c6240a2 | ||
|  | 60cab840cb | ||
|  | 83a4380dab | ||
|  | de84fe8d98 | ||
|  | ed3cbfdb8e | ||
|  | fda44ca17d | ||
|  | 272025bb07 | ||
|  | 8e92bcf1b2 | ||
|  | 84f1ffdefe | ||
|  | 7e25450054 | ||
|  | 4a563fa266 | ||
|  | aa4c0ec000 | ||
|  | e1ecfbdc43 | ||
|  | a4e122a82e | ||
|  | 93216e8fb7 | ||
|  | 16272c210d | ||
|  | e104b00da1 | ||
|  | ce5c6bcc08 | ||
|  | 8694ce31fe | ||
|  | d960e5eadd | ||
|  | 2dc71e87a3 | ||
|  | 6bf17edde2 | ||
|  | 88573d515d | ||
|  | 89b9f77823 | ||
|  | 765d9be17d | ||
|  | 7135373008 | ||
|  | ee269884fc | ||
|  | 387540d5f1 | ||
|  | 2eba7b42a8 | ||
|  | 07115d26c7 | ||
|  | c43ed815a0 | ||
|  | ff01e36d12 | ||
|  | ac4798b16c | ||
|  | d4e14fed0e | ||
|  | 5f91259344 | ||
|  | 20a9d9645d | ||
|  | c86f6b4abd | ||
|  | d66489b5b2 | ||
|  | b743ee9f0c | ||
|  | 95ba69c00a | ||
|  | 2ac273739c | ||
|  | 5b4d28708c | ||
|  | 4cc4383488 | ||
|  | 8935232248 | ||
|  | 5c6dd2f172 | ||
|  | eeeb7ef5b9 | ||
|  | 2efc9c1178 | ||
|  | a84c46f6e3 | ||
|  | a5c3dcdd02 | ||
|  | 46f7a75eb7 | ||
|  | 94b6710c5b | ||
|  | d8dd3da9ab | ||
|  | 803ced004a | ||
|  | 0ea7d36ad0 | ||
|  | 87aafab759 | ||
|  | 994d310abd | ||
|  | 228cdcf05e | ||
|  | 42598e352c | ||
|  | 36a9e4d1da | ||
|  | 456dfd0dea | ||
|  | 155457e2b5 | ||
|  | b5c91485bf | ||
|  | c959cf7870 | ||
|  | 5878c88636 | ||
|  | ddcef2fb19 | ||
|  | 493d124c07 | ||
|  | f42060c616 | ||
|  | 834facc932 | ||
|  | f82d0b76ee | ||
|  | c25d225275 | ||
|  | c503a274b5 | ||
|  | 087069d215 | ||
|  | 826a6dd114 | ||
|  | f31483838d | ||
|  | d8a9b633d9 | ||
|  | c060e4466a | ||
|  | a9951376f4 | ||
|  | bda0c8f5e3 | ||
|  | 71902f23a2 | ||
|  | dfd6c85569 | ||
|  | 0e41b2cc1a | ||
|  | e5c81d0702 | ||
|  | 6caf7d4d5a | ||
|  | 98e87c8afb | ||
|  | d9e0f80d50 | ||
|  | 6396fdb5ff | ||
|  | 2470b53373 | ||
|  | 16334e92ca | ||
|  | c22d98a8ec | ||
|  | 28617afbb9 | ||
|  | 0c3bc42bec | ||
|  | e3d9745df1 | ||
|  | b8471c1015 | ||
|  | 045b09c9ef | ||
|  | 4ac07b97d3 | ||
|  | 34c847c17f | ||
|  | f694e557e1 | 
| @@ -100,7 +100,7 @@ Assignment | ||||
| </UL> | ||||
|  | ||||
| <h3>See also</h3> | ||||
| <a href="http://www.sgi.com/Technology/STL/DefaultConstructible.html">DefaultConstructible</A> | ||||
| <a href="http://www.sgi.com/tech/stl/DefaultConstructible.html">DefaultConstructible</A> | ||||
| and  | ||||
| <A href="./CopyConstructible.html">CopyConstructible</A> | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|   -- purpose.  It is provided "as is" without express or implied warranty. | ||||
|   --> | ||||
| <Head> | ||||
| <Title>CopyConstructible</Title> | ||||
| <Title>Copy Constructible</Title> | ||||
| </HEAD> | ||||
| <BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"  | ||||
|         ALINK="#ff0000">  | ||||
| @@ -19,10 +19,10 @@ | ||||
|      ALT="C++ Boost" width="277" height="86">  | ||||
| <!--end header--> | ||||
| <BR Clear> | ||||
| <H1>CopyConstructible</H1> | ||||
| <H1>Copy Constructible</H1> | ||||
|  | ||||
| <h3>Description</h3> | ||||
| A type is CopyConstructible if it is possible to copy objects of that | ||||
| A type is Copy Constructible if it is possible to copy objects of that | ||||
| type. | ||||
|  | ||||
| <h3>Notation</h3> | ||||
| @@ -32,7 +32,7 @@ type. | ||||
| <tt>T</tt> | ||||
| </TD> | ||||
| <TD VAlign=top> | ||||
| is type that is a model of CopyConstructible | ||||
| is type that is a model of Copy Constructible | ||||
| </TD> | ||||
| </TR> | ||||
|  | ||||
| @@ -194,9 +194,9 @@ denotes the address of <tt>u</tt> | ||||
|  | ||||
| <h3>See also</h3> | ||||
| <A | ||||
| href="http://www.sgi.com/Technology/STL/DefaultConstructible.html">DefaultConstructible</A> | ||||
| href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default Constructible</A> | ||||
| and  | ||||
| <A href="http://www.sgi.com/Technology/STL/Assignable.html">Assignable</A> | ||||
| <A hrefa="./Assignable.html">Assignable</A> | ||||
|  | ||||
| <br> | ||||
| <HR> | ||||
|   | ||||
| @@ -196,7 +196,7 @@ satisfies the definition of a <i>partial ordering</i>.  The definition of | ||||
| a <i>strict weak ordering</i> is stricter, and the definition of a | ||||
| <i>total ordering</i> is stricter still. | ||||
| <h3>See also</h3> | ||||
| <A href="http://www.sgi.com/Technology/STL/EqualityComparable.html">EqualityComparable</A>, <A href="http://www.sgi.com/Technology/STL/StrictWeakOrdering.html">StrictWeakOrdering</A> | ||||
| <A href="http://www.sgi.com/tech/stl/EqualityComparable.html">EqualityComparable</A>, <A href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">StrictWeakOrdering</A> | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -21,21 +21,21 @@ | ||||
|  | ||||
| <H2> | ||||
| <A NAME="concept:MultiPassInputIterator"></A> | ||||
| MultiPassInputIterator | ||||
| Multi-Pass Input Iterator | ||||
| </H2> | ||||
|  | ||||
| This concept is a refinement of <a | ||||
| href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</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 | ||||
| MultiPassInputIterator is very similar to the <a | ||||
| href="http://www.sgi.com/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a>. 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/Technology/STL/ForwardIterator.hmtl">ForwardIterator</a> | ||||
| href="http://www.sgi.com/tech/stl/ForwardIterator.hmtl">Forward Iterator</a> | ||||
| requires the <TT>reference</TT> type to be <TT>value_type&</TT>, whereas | ||||
| MultiPassInputIterator is like <a | ||||
| href="http://www.sgi.com/Technology/STL/InputIterator.html">InputIterator</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>. | ||||
|  | ||||
| @@ -44,29 +44,29 @@ in that the <TT>reference</TT> type merely has to be convertible to | ||||
|  | ||||
| comments by Valentin Bonnard: | ||||
|  | ||||
| <p> I think that introducing MultiPassInputIterator isn't the right | ||||
| solution. Do you also want to define MultiPassBidirectionnalIterator | ||||
| and MultiPassRandomAccessIterator ? I don't, definitly. It only | ||||
| <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 RandomAccess are about | ||||
| <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 MultiPassInputIterator | ||||
| is just called a ForwardIterator. | ||||
| immutabillity.  With these clean concepts, your Multi-Pass Input Iterator | ||||
| is just called a Forward Iterator. | ||||
|  | ||||
| <p>                 | ||||
| Other translations are:<br> | ||||
| std::ForwardIterator -> ForwardIterator & LvalueIterator<br> | ||||
| std::BidirectionnalIterator -> BidirectionnalIterator & LvalueIterator<br> | ||||
| std::RandomAccessIterator -> RandomAccessIterator & LvalueIterator<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  | ||||
| ForwardIterator which is allowed on std::ForwardIterator is  | ||||
| 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> | ||||
| @@ -75,9 +75,9 @@ reply by Jeremy Siek: | ||||
| <p> | ||||
| The above analysis by Valentin is right on. Of course, there is | ||||
| the problem with backward compatibility. The current STL implementations | ||||
| are based on the old definition of ForwardIterator. The right course | ||||
| of action is to get ForwardIterator, etc. changed in the C++ standard. | ||||
| Once that is done we can drop MultiPassInputIterator. | ||||
| 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> | ||||
|   | ||||
| @@ -1,424 +0,0 @@ | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Copyright (c) 1999 | ||||
|  * Dr John Maddock | ||||
|  * | ||||
|  * Permission to use, copy, modify, distribute and sell this software | ||||
|  * and its documentation for any purpose is hereby granted without fee, | ||||
|  * provided that the above copyright notice appear in all copies and | ||||
|  * that both that copyright notice and this permission notice appear | ||||
|  * in supporting documentation.  Dr John Maddock makes no representations | ||||
|  * about the suitability of this software for any purpose. | ||||
|  * It is provided "as is" without express or implied warranty. | ||||
|  * | ||||
|  * This file provides some example of type_traits usage - | ||||
|  * by "optimising" various algorithms: | ||||
|  * | ||||
|  * opt::copy - optimised for trivial copy (cf std::copy) | ||||
|  * opt::fill - optimised for trivial copy/small types (cf std::fill) | ||||
|  * opt::destroy_array - an example of optimisation based upon omitted destructor calls | ||||
|  * opt::iter_swap - uses type_traits to determine whether the iterator is a proxy | ||||
|  *                  in which case it uses a "safe" approach, otherwise calls swap | ||||
|  *                  on the assumption that swap may be specialised for the pointed-to type. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /* Release notes: | ||||
|    23rd July 2000: | ||||
|       Added explicit failure for broken compilers that don't support these examples. | ||||
|       Fixed broken gcc support (broken using directive). | ||||
|       Reordered tests slightly. | ||||
| */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <typeinfo> | ||||
| #include <algorithm> | ||||
| #include <iterator> | ||||
| #include <vector> | ||||
| #include <memory> | ||||
|  | ||||
| #include <boost/timer.hpp> | ||||
| #include <boost/type_traits.hpp> | ||||
| #include <boost/call_traits.hpp> | ||||
|  | ||||
| using std::cout; | ||||
| using std::endl; | ||||
| using std::cin; | ||||
|  | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
| #error "Sorry, without template partial specialisation support there isn't anything to test here..." | ||||
| #endif | ||||
|  | ||||
| namespace opt{ | ||||
|  | ||||
| // | ||||
| // algorithm destroy_array: | ||||
| // The reverse of std::unitialized_copy, takes a block of | ||||
| // unitialized memory and calls destructors on all objects therein. | ||||
| // | ||||
|  | ||||
| namespace detail{ | ||||
|  | ||||
| template <bool> | ||||
| struct array_destroyer | ||||
| { | ||||
|    template <class T> | ||||
|    static void destroy_array(T* i, T* j){ do_destroy_array(i, j); } | ||||
| }; | ||||
|  | ||||
| template <> | ||||
| struct array_destroyer<true> | ||||
| { | ||||
|    template <class T> | ||||
|    static void destroy_array(T*, T*){} | ||||
| }; | ||||
|  | ||||
| template <class T> | ||||
| void do_destroy_array(T* first, T* last) | ||||
| { | ||||
|    while(first != last) | ||||
|    { | ||||
|       first->~T(); | ||||
|       ++first; | ||||
|    } | ||||
| } | ||||
|  | ||||
| }; // namespace detail | ||||
|  | ||||
| template <class T> | ||||
| inline void destroy_array(T* p1, T* p2) | ||||
| { | ||||
|    detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2); | ||||
| } | ||||
|  | ||||
| // | ||||
| // unoptimised versions of destroy_array: | ||||
| // | ||||
| template <class T> | ||||
| void destroy_array1(T* first, T* last) | ||||
| { | ||||
|    while(first != last) | ||||
|    { | ||||
|       first->~T(); | ||||
|       ++first; | ||||
|    } | ||||
| } | ||||
| template <class T> | ||||
| void destroy_array2(T* first, T* last) | ||||
| { | ||||
|    for(; first != last; ++first) first->~T(); | ||||
| } | ||||
|  | ||||
|  | ||||
| // | ||||
| // opt::copy | ||||
| // same semantics as std::copy | ||||
| // calls memcpy where appropiate. | ||||
| // | ||||
|  | ||||
| namespace detail{ | ||||
|  | ||||
| template <bool b> | ||||
| struct copier | ||||
| { | ||||
|    template<typename I1, typename I2> | ||||
|    static I2 do_copy(I1 first, I1 last, I2 out); | ||||
| }; | ||||
|  | ||||
| template <bool b> | ||||
| template<typename I1, typename I2> | ||||
| I2 copier<b>::do_copy(I1 first, I1 last, I2 out) | ||||
| { | ||||
|    while(first != last) | ||||
|    { | ||||
|       *out = *first; | ||||
|       ++out; | ||||
|       ++first; | ||||
|    } | ||||
|    return out; | ||||
| } | ||||
|  | ||||
| template <> | ||||
| struct copier<true> | ||||
| { | ||||
|    template<typename I1, typename I2> | ||||
|    static I2* do_copy(I1* first, I1* last, I2* out) | ||||
|    { | ||||
|       memcpy(out, first, (last-first)*sizeof(I2)); | ||||
|       return out+(last-first); | ||||
|    } | ||||
| }; | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| template<typename I1, typename I2> | ||||
| inline I2 copy(I1 first, I1 last, I2 out) | ||||
| { | ||||
|    typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t; | ||||
|    typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t; | ||||
|    enum{ can_opt = boost::is_same<v1_t, v2_t>::value | ||||
|                    && boost::is_pointer<I1>::value | ||||
|                    && boost::is_pointer<I2>::value | ||||
|                    && boost::has_trivial_assign<v1_t>::value }; | ||||
|    return detail::copier<can_opt>::do_copy(first, last, out); | ||||
| } | ||||
|  | ||||
| // | ||||
| // fill | ||||
| // same as std::fill, uses memset where appropriate, along with call_traits | ||||
| // to "optimise" parameter passing. | ||||
| // | ||||
| namespace detail{ | ||||
|  | ||||
| template <bool opt> | ||||
| struct filler | ||||
| { | ||||
|    template <typename I, typename T> | ||||
|    static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val); | ||||
|  }; | ||||
|  | ||||
| template <bool b> | ||||
| template <typename I, typename T> | ||||
| void filler<b>::do_fill(I first, I last, typename boost::call_traits<T>::param_type val) | ||||
| { | ||||
|    while(first != last) | ||||
|    { | ||||
|       *first = val; | ||||
|       ++first; | ||||
|    } | ||||
| } | ||||
|  | ||||
| template <> | ||||
| struct filler<true> | ||||
| { | ||||
|    template <typename I, typename T> | ||||
|    static void do_fill(I first, I last, T val) | ||||
|    { | ||||
|       std::memset(first, val, last-first); | ||||
|    } | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| template <class I, class T> | ||||
| inline void fill(I first, I last, const T& val) | ||||
| { | ||||
|    enum{ can_opt = boost::is_pointer<I>::value | ||||
|                    && boost::is_arithmetic<T>::value | ||||
|                    && (sizeof(T) == 1) }; | ||||
|    typedef detail::filler<can_opt> filler_t; | ||||
|    filler_t::template do_fill<I,T>(first, last, val); | ||||
| } | ||||
|  | ||||
| // | ||||
| // iter_swap: | ||||
| // tests whether iterator is a proxying iterator or not, and | ||||
| // uses optimal form accordingly: | ||||
| // | ||||
| namespace detail{ | ||||
|  | ||||
| template <bool b> | ||||
| struct swapper | ||||
| { | ||||
|    template <typename I> | ||||
|    static void do_swap(I one, I two) | ||||
|    { | ||||
|       typedef typename std::iterator_traits<I>::value_type v_t; | ||||
|       v_t v = *one; | ||||
|       *one = *two; | ||||
|       *two = v; | ||||
|    } | ||||
| }; | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| using std::swap; | ||||
| #endif | ||||
|  | ||||
| template <> | ||||
| struct swapper<true> | ||||
| { | ||||
|    template <typename I> | ||||
|    static void do_swap(I one, I two) | ||||
|    { | ||||
|       using std::swap; | ||||
|       swap(*one, *two); | ||||
|    } | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| template <typename I1, typename I2> | ||||
| inline void iter_swap(I1 one, I2 two) | ||||
| { | ||||
|    typedef typename std::iterator_traits<I1>::reference r1_t; | ||||
|    typedef typename std::iterator_traits<I2>::reference r2_t; | ||||
|    enum{ can_opt = boost::is_reference<r1_t>::value && boost::is_reference<r2_t>::value && boost::is_same<r1_t, r2_t>::value }; | ||||
|    detail::swapper<can_opt>::do_swap(one, two); | ||||
| } | ||||
|  | ||||
|  | ||||
| };   // namespace opt | ||||
|  | ||||
| // | ||||
| // define some global data: | ||||
| // | ||||
| const int array_size = 1000; | ||||
| int i_array[array_size] = {0,}; | ||||
| const int ci_array[array_size] = {0,}; | ||||
| char c_array[array_size] = {0,}; | ||||
| const char cc_array[array_size] = { 0,}; | ||||
|  | ||||
| const int iter_count = 1000000; | ||||
|  | ||||
|  | ||||
| int main() | ||||
| { | ||||
|    // | ||||
|    // test destroy_array, | ||||
|    // compare destruction time of an array of ints | ||||
|    // with unoptimised form. | ||||
|    // | ||||
|    cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl; | ||||
|    cout << "testing destroy_array...\n" | ||||
|     "[Some compilers may be able to optimise the \"unoptimised\"\n versions as well as type_traits does.]" << endl; | ||||
|    /*cache load*/ opt::destroy_array(i_array, i_array + array_size); | ||||
|    boost::timer t; | ||||
|    double result; | ||||
|    int i; | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::destroy_array(i_array, i_array + array_size); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "destroy_array<int>: " << result << endl; | ||||
|    /*cache load*/ opt::destroy_array1(i_array, i_array + array_size); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::destroy_array1(i_array, i_array + array_size); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "destroy_array<int>(unoptimised#1): " << result << endl; | ||||
|    /*cache load*/ opt::destroy_array2(i_array, i_array + array_size); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::destroy_array2(i_array, i_array + array_size); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "destroy_array<int>(unoptimised#2): " << result << endl << endl; | ||||
|  | ||||
|    cout << "testing fill(char)...\n" | ||||
|    "[Some standard library versions may already perform this optimisation.]" << endl; | ||||
|    /*cache load*/ opt::fill<char*, char>(c_array, c_array + array_size, (char)3); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::fill<char*, char>(c_array, c_array + array_size, (char)3); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "opt::fill<char*, char>: " << result << endl; | ||||
|    /*cache load*/ std::fill(c_array, c_array + array_size, (char)3); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       std::fill(c_array, c_array + array_size, (char)3); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "std::fill<char*, char>: " << result << endl << endl; | ||||
|  | ||||
|    cout << "testing fill(int)...\n" | ||||
|    "[Tests the effect of call_traits pass-by-value optimisation -\nthe value of this optimisation may depend upon hardware characteristics.]" << endl; | ||||
|    /*cache load*/ opt::fill<int*, int>(i_array, i_array + array_size, 3); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::fill<int*, int>(i_array, i_array + array_size, 3); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "opt::fill<int*, int>: " << result << endl; | ||||
|    /*cache load*/ std::fill(i_array, i_array + array_size, 3); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       std::fill(i_array, i_array + array_size, 3); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "std::fill<int*, int>: " << result << endl << endl; | ||||
|  | ||||
|    cout << "testing copy...\n" | ||||
|    "[Some standard library versions may already perform this optimisation.]" << endl; | ||||
|    /*cache load*/ opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "opt::copy<const int*, int*>: " << result << endl; | ||||
|    /*cache load*/ std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "std::copy<const int*, int*>: " << result << endl; | ||||
|    /*cache load*/ opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "standard \"unoptimised\" copy: " << result << endl << endl; | ||||
|  | ||||
|    /*cache load*/ opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "opt::copy<const char*, char*>: " << result << endl; | ||||
|    /*cache load*/ std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "std::copy<const char*, char*>: " << result << endl; | ||||
|    /*cache load*/ opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    t.restart(); | ||||
|    for(i = 0; i < iter_count; ++i) | ||||
|    { | ||||
|       opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array); | ||||
|    } | ||||
|    result = t.elapsed(); | ||||
|    cout << "standard \"unoptimised\" copy: " << result << endl << endl; | ||||
|  | ||||
|  | ||||
|    // | ||||
|    // testing iter_swap | ||||
|    // really just a check that it does in fact compile... | ||||
|    std::vector<int> v1; | ||||
|    v1.push_back(0); | ||||
|    v1.push_back(1); | ||||
|    std::vector<bool> v2; | ||||
|    v2.push_back(0); | ||||
|    v2.push_back(1); | ||||
|    opt::iter_swap(v1.begin(), v1.begin()+1); | ||||
|    opt::iter_swap(v2.begin(), v2.begin()+1); | ||||
|  | ||||
|    cout << "Press any key to exit..."; | ||||
|    cin.get(); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -1,489 +0,0 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>C++ Type traits</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080"> | ||||
|  | ||||
| <h2 align="center">C++ Type traits</h2> | ||||
| <p align="center"><em>by John Maddock and Steve Cleary</em></p> | ||||
| <p align="center"><em>This is a draft of an article that will appear in a future | ||||
| issue of </em><a href="http://www.ddj.com"><em>Dr Dobb's Journal</em></a></p> | ||||
| <p>Generic programming (writing code which works with any data type meeting a | ||||
| set of requirements) has become the method of choice for providing reusable | ||||
| code. However, there are times in generic programming when "generic" | ||||
| just isn't good enough - sometimes the differences between types are too large | ||||
| for an efficient generic implementation. This is when the traits technique | ||||
| becomes important - by encapsulating those properties that need to be considered | ||||
| on a type by type basis inside a traits class, we can minimise the amount of | ||||
| code that has to differ from one type to another, and maximise the amount of | ||||
| generic code.</p> | ||||
| <p>Consider an example: when working with character strings, one common | ||||
| operation is to determine the length of a null terminated string. Clearly it's | ||||
| possible to write generic code that can do this, but it turns out that there are | ||||
| much more efficient methods available: for example, the C library functions <font size="2" face="Courier New">strlen</font> | ||||
| and <font size="2" face="Courier New">wcslen</font> are usually written in | ||||
| assembler, and with suitable hardware support can be considerably faster than a | ||||
| generic version written in C++. The authors of the C++ standard library realised | ||||
| this, and abstracted the properties of <font size="2" face="Courier New">char</font> | ||||
| and <font size="2" face="Courier New">wchar_t</font> into the class <font size="2" face="Courier New">char_traits</font>. | ||||
| Generic code that works with character strings can simply use <font size="2" face="Courier New">char_traits<>::length</font> | ||||
| to determine the length of a null terminated string, safe in the knowledge that | ||||
| specialisations of <font size="2" face="Courier New">char_traits</font> will use | ||||
| the most appropriate method available to them.</p> | ||||
| <h4>Type traits</h4> | ||||
| <p>Class <font size="2" face="Courier New">char_traits</font> is a classic | ||||
| example of a collection of type specific properties wrapped up in a single class | ||||
| - what Nathan Myers termed a <i>baggage class</i>[1]. In the Boost type-traits | ||||
| library, we[2] have written a set of very specific traits classes, each of which | ||||
| encapsulate a single trait from the C++ type system; for example, is a type a | ||||
| pointer or a reference type? Or does a type have a trivial constructor, or a | ||||
| const-qualifier? The type-traits classes share a unified design: each class has | ||||
| a single member <i>value</i>, a compile-time constant that is true if the type | ||||
| has the specified property, and false otherwise. As we will show, these classes | ||||
| can be used in generic programming to determine the properties of a given type | ||||
| and introduce optimisations that are appropriate for that case.</p> | ||||
| <p>The type-traits library also contains a set of classes that perform a | ||||
| specific transformation on a type; for example, they can remove a top-level | ||||
| const or volatile qualifier from a type. Each class that performs a | ||||
| transformation defines a single typedef-member <i>type</i> that is the result of | ||||
| the transformation. All of the type-traits classes are defined inside namespace <font size="2" face="Courier New">boost</font>; | ||||
| for brevity, namespace-qualification is omitted in most of the code samples | ||||
| given.</p> | ||||
| <h4>Implementation</h4> | ||||
| <p>There are far too many separate classes contained in the type-traits library | ||||
| to give a full implementation here - see the source code in the Boost library | ||||
| for the full details - however, most of the implementation is fairly repetitive | ||||
| anyway, so here we will just give you a flavour for how some of the classes are | ||||
| implemented. Beginning with possibly the simplest class in the library, is_void<T> | ||||
| has a member <i>value</i> that is true only if T is void.</p> | ||||
| <pre>template <typename T>  | ||||
| struct is_void | ||||
| { static const bool value = false; }; | ||||
|  | ||||
| template <>  | ||||
| struct is_void<void> | ||||
| { static const bool value = true; };</pre> | ||||
| <p>Here we define a primary version of the template class <font size="2" face="Courier New">is_void</font>, | ||||
| and provide a full-specialisation when T is void. While full specialisation of a | ||||
| template class is an important technique, sometimes we need a solution that is | ||||
| halfway between a fully generic solution, and a full specialisation. This is | ||||
| exactly the situation for which the standards committee defined partial | ||||
| template-class specialisation. As an example, consider the class | ||||
| boost::is_pointer<T>: here we needed a primary version that handles all | ||||
| the cases where T is not a pointer, and a partial specialisation to handle all | ||||
| the cases where T is a pointer:</p> | ||||
| <pre>template <typename T>  | ||||
| struct is_pointer  | ||||
| { static const bool value = false; }; | ||||
|  | ||||
| template <typename T>  | ||||
| struct is_pointer<T*>  | ||||
| { static const bool value = true; };</pre> | ||||
| <p>The syntax for partial specialisation is somewhat arcane and could easily | ||||
| occupy an article in its own right; like full specialisation, in order to write | ||||
| a partial specialisation for a class, you must first declare the primary | ||||
| template. The partial specialisation contains an extra <<EFBFBD>> after the | ||||
| class name that contains the partial specialisation parameters; these define the | ||||
| types that will bind to that partial specialisation rather than the default | ||||
| template. The rules for what can appear in a partial specialisation are somewhat | ||||
| convoluted, but as a rule of thumb if you can legally write two function | ||||
| overloads of the form:</p> | ||||
| <pre>void foo(T); | ||||
| void foo(U);</pre> | ||||
| <p>Then you can also write a partial specialisation of the form:</p> | ||||
| <pre>template <typename T> | ||||
| class c{ /*details*/ }; | ||||
|  | ||||
| template <typename T> | ||||
|  | ||||
| class c<U>{ /*details*/ };</pre> | ||||
| <p>This rule is by no means foolproof, but it is reasonably simple to remember | ||||
| and close enough to the actual rule to be useful for everyday use.</p> | ||||
| <p>As a more complex example of partial specialisation consider the class | ||||
| remove_bounds<T>. This class defines a single typedef-member <i>type</i> | ||||
| that is the same type as T but with any top-level array bounds removed; this is | ||||
| an example of a traits class that performs a transformation on a type:</p> | ||||
| <pre>template <typename T>  | ||||
| struct remove_bounds | ||||
| { typedef T type; }; | ||||
|  | ||||
| template <typename T, std::size_t N>  | ||||
| struct remove_bounds<T[N]> | ||||
| { typedef T type; };</pre> | ||||
| <p>The aim of remove_bounds is this: imagine a generic algorithm that is passed | ||||
| an array type as a template parameter, <font size="2" face="Courier New">remove_bounds</font> | ||||
| provides a means of determining the underlying type of the array. For example <code>remove_bounds<int[4][5]>::type</code> | ||||
| would evaluate to the type <code>int[5]</code>. This example also shows that the | ||||
| number of template parameters in a partial specialisation does not have to match | ||||
| the number in the default template. However, the number of parameters that | ||||
| appear after the class name do have to match the number and type of the | ||||
| parameters in the default template.</p> | ||||
| <h4>Optimised copy</h4> | ||||
| <p>As an example of how the type traits classes can be used, consider the | ||||
| standard library algorithm copy:</p> | ||||
| <pre>template<typename Iter1, typename Iter2> | ||||
| Iter2 copy(Iter1 first, Iter1 last, Iter2 out);</pre> | ||||
| <p>Obviously, there's no problem writing a generic version of copy that works | ||||
| for all iterator types Iter1 and Iter2; however, there are some circumstances | ||||
| when the copy operation can best be performed by a call to <font size="2" face="Courier New">memcpy</font>. | ||||
| In order to implement copy in terms of <font size="2" face="Courier New">memcpy</font> | ||||
| all of the following conditions need to be met:</p> | ||||
| <ul> | ||||
|   <li>Both of the iterator types Iter1 and Iter2 must be pointers.</li> | ||||
|   <li>Both Iter1 and Iter2 must point to the same type - excluding <font size="2" face="Courier New">const</font> | ||||
|     and <font size="2" face="Courier New">volatile</font>-qualifiers.</li> | ||||
|   <li>The type pointed to by Iter1 must have a trivial assignment operator.</li> | ||||
| </ul> | ||||
| <p>By trivial assignment operator we mean that the type is either a scalar | ||||
| type[3] or:</p> | ||||
| <ul> | ||||
|   <li>The type has no user defined assignment operator.</li> | ||||
|   <li>The type does not have any data members that are references.</li> | ||||
|   <li>All base classes, and all data member objects must have trivial assignment | ||||
|     operators.</li> | ||||
| </ul> | ||||
| <p>If all these conditions are met then a type can be copied using <font size="2" face="Courier New">memcpy</font> | ||||
| rather than using a compiler generated assignment operator. The type-traits | ||||
| library provides a class <i>has_trivial_assign</i>, such that <code>has_trivial_assign<T>::value</code> | ||||
| is true only if T has a trivial assignment operator. This class "just | ||||
| works" for scalar types, but has to be explicitly specialised for | ||||
| class/struct types that also happen to have a trivial assignment operator. In | ||||
| other words if <i>has_trivial_assign</i> gives the wrong answer, it will give | ||||
| the "safe" wrong answer - that trivial assignment is not allowable.</p> | ||||
| <p>The code for an optimised version of copy that uses <font size="2" face="Courier New">memcpy</font> | ||||
| where appropriate is given in listing 1. The code begins by defining a template | ||||
| class <i>copier</i>, that takes a single Boolean template parameter, and has a | ||||
| static template member function <font size="2" face="Courier New">do_copy</font> | ||||
| which performs the generic version of <font size="2">copy</font> (in other words | ||||
| the "slow but safe version"). Following that there is a specialisation | ||||
| for <i>copier<true></i>: again this defines a static template member | ||||
| function <font size="2" face="Courier New">do_copy</font>, but this version uses | ||||
| memcpy to perform an "optimised" copy.</p> | ||||
| <p>In order to complete the implementation, what we need now is a version of | ||||
| copy, that calls <code>copier<true>::do_copy</code> if it is safe to use <font size="2" face="Courier New">memcpy</font>, | ||||
| and otherwise calls <code>copier<false>::do_copy</code> to do a | ||||
| "generic" copy. This is what the version in listing 1 does. To | ||||
| understand how the code works look at the code for <font size="2" face="Courier New">copy</font> | ||||
| and consider first the two typedefs <i>v1_t</i> and <i>v2_t</i>. These use <code>std::iterator_traits<Iter1>::value_type</code> | ||||
| to determine what type the two iterators point to, and then feed the result into | ||||
| another type-traits class <i>remove_cv</i> that removes the top-level | ||||
| const-volatile-qualifiers: this will allow copy to compare the two types without | ||||
| regard to const- or volatile-qualifiers. Next, <font size="2" face="Courier New">copy</font> | ||||
| declares an enumerated value <i>can_opt</i> that will become the template | ||||
| parameter to copier - declaring this here as a constant is really just a | ||||
| convenience - the value could be passed directly to class <font size="2" face="Courier New">copier</font>. | ||||
| The value of <i>can_opt</i> is computed by verifying that all of the following | ||||
| are true:</p> | ||||
| <ul> | ||||
|   <li>first that the two iterators point to the same type by using a type-traits | ||||
|     class <i>is_same</i>.</li> | ||||
|   <li>Then that both iterators are real pointers - using the class <i>is_pointer</i> | ||||
|     described above.</li> | ||||
|   <li>Finally that the pointed-to types have a trivial assignment operator using | ||||
|     <i>has_trivial_assign</i>.</li> | ||||
| </ul> | ||||
| <p>Finally we can use the value of <i>can_opt</i> as the template argument to | ||||
| copier - this version of copy will now adapt to whatever parameters are passed | ||||
| to it, if its possible to use <font size="2" face="Courier New">memcpy</font>, | ||||
| then it will do so, otherwise it will use a generic copy.</p> | ||||
| <h4>Was it worth it?</h4> | ||||
| <p>It has often been repeated in these columns that "premature optimisation | ||||
| is the root of all evil" [4]. So the question must be asked: was our | ||||
| optimisation premature? To put this in perspective the timings for our version | ||||
| of copy compared a conventional generic copy[5] are shown in table 1.</p> | ||||
| <p>Clearly the optimisation makes a difference in this case; but, to be fair, | ||||
| the timings are loaded to exclude cache miss effects - without this accurate | ||||
| comparison between algorithms becomes difficult. However, perhaps we can add a | ||||
| couple of caveats to the premature optimisation rule:</p> | ||||
| <ul> | ||||
|   <li>If you use the right algorithm for the job in the first place then | ||||
|     optimisation will not be required; in some cases, <font size="2" face="Courier New">memcpy</font> | ||||
|     is the right algorithm.</li> | ||||
|   <li>If a component is going to be reused in many places by many people then | ||||
|     optimisations may well be worthwhile where they would not be so for a single | ||||
|     case - in other words, the likelihood that the optimisation will be | ||||
|     absolutely necessary somewhere, sometime is that much higher. Just as | ||||
|     importantly the perceived value of the stock implementation will be higher: | ||||
|     there is no point standardising an algorithm if users reject it on the | ||||
|     grounds that there are better, more heavily optimised versions available.</li> | ||||
| </ul> | ||||
| <h4>Table 1: Time taken to copy 1000 elements using copy<const T*, T*> | ||||
| (times in micro-seconds)</h4> | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="529"> | ||||
|   <tr> | ||||
|     <td valign="top" width="33%"> | ||||
|       <p align="center">Version</p> | ||||
|     </td> | ||||
|     <td valign="top" width="33%"> | ||||
|       <p align="center">T</p> | ||||
|     </td> | ||||
|     <td valign="top" width="33%"> | ||||
|       <p align="center">Time</p> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="33%">"Optimised" copy</td> | ||||
|     <td valign="top" width="33%">char</td> | ||||
|     <td valign="top" width="33%">0.99</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="33%">Conventional copy</td> | ||||
|     <td valign="top" width="33%">char</td> | ||||
|     <td valign="top" width="33%">8.07</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="33%">"Optimised" copy</td> | ||||
|     <td valign="top" width="33%">int</td> | ||||
|     <td valign="top" width="33%">2.52</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="33%">Conventional copy</td> | ||||
|     <td valign="top" width="33%">int</td> | ||||
|     <td valign="top" width="33%">8.02</td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p> </p> | ||||
| <h4>Pair of References</h4> | ||||
| <p>The optimised copy example shows how type traits may be used to perform | ||||
| optimisation decisions at compile-time. Another important usage of type traits | ||||
| is to allow code to compile that otherwise would not do so unless excessive | ||||
| partial specialization is used. This is possible by delegating partial | ||||
| specialization to the type traits classes. Our example for this form of usage is | ||||
| a pair that can hold references [6].</p> | ||||
| <p>First, let us examine the definition of "std::pair", omitting the | ||||
| comparision operators, default constructor, and template copy constructor for | ||||
| simplicity:</p> | ||||
| <pre>template <typename T1, typename T2>  | ||||
| struct pair  | ||||
| { | ||||
|   typedef T1 first_type; | ||||
|   typedef T2 second_type; | ||||
|  | ||||
|   T1 first; | ||||
|   T2 second; | ||||
|  | ||||
|   pair(const T1 & nfirst, const T2 & nsecond) | ||||
|   :first(nfirst), second(nsecond) { } | ||||
| };</pre> | ||||
| <p>Now, this "pair" cannot hold references as it currently stands, | ||||
| because the constructor would require taking a reference to a reference, which | ||||
| is currently illegal [7]. Let us consider what the constructor's parameters | ||||
| would have to be in order to allow "pair" to hold non-reference types, | ||||
| references, and constant references:</p> | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="638"> | ||||
|   <tr> | ||||
|     <td valign="top" width="50%">Type of "T1"</td> | ||||
|     <td valign="top" width="50%">Type of parameter to initializing constructor</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>T</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>T &</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="50%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p>A little familiarity with the type traits classes allows us to construct a | ||||
| single mapping that allows us to determine the type of parameter from the type | ||||
| of the contained class. The type traits classes provide a transformation "add_reference", | ||||
| which adds a reference to its type, unless it is already a reference.</p> | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="580"> | ||||
|   <tr> | ||||
|     <td valign="top" width="21%">Type of "T1"</td> | ||||
|     <td valign="top" width="27%">Type of "const T1"</td> | ||||
|     <td valign="top" width="53%">Type of "add_reference<const | ||||
|       T1>::type"</td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="21%"> | ||||
|       <pre>T</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="27%"> | ||||
|       <pre>const T</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="53%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="21%"> | ||||
|       <pre>T &</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="27%"> | ||||
|       <pre>T & [8]</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="53%"> | ||||
|       <pre>T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td valign="top" width="21%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="27%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|     <td valign="top" width="53%"> | ||||
|       <pre>const T &</pre> | ||||
|     </td> | ||||
|   </tr> | ||||
| </table> | ||||
| <p>This allows us to build a primary template definition for "pair" | ||||
| that can contain non-reference types, reference types, and constant reference | ||||
| types:</p> | ||||
| <pre>template <typename T1, typename T2>  | ||||
| struct pair  | ||||
| { | ||||
|   typedef T1 first_type; | ||||
|   typedef T2 second_type; | ||||
|  | ||||
|   T1 first; | ||||
|   T2 second; | ||||
|  | ||||
|   pair(boost::add_reference<const T1>::type nfirst, | ||||
|        boost::add_reference<const T2>::type nsecond) | ||||
|   :first(nfirst), second(nsecond) { } | ||||
| };</pre> | ||||
| <p>Add back in the standard comparision operators, default constructor, and | ||||
| template copy constructor (which are all the same), and you have a std::pair | ||||
| that can hold reference types!</p> | ||||
| <p>This same extension <i>could</i> have been done using partial template | ||||
| specialization of "pair", but to specialize "pair" in this | ||||
| way would require three partial specializations, plus the primary template. Type | ||||
| traits allows us to define a single primary template that adjusts itself | ||||
| auto-magically to any of these partial specializations, instead of a brute-force | ||||
| partial specialization approach. Using type traits in this fashion allows | ||||
| programmers to delegate partial specialization to the type traits classes, | ||||
| resulting in code that is easier to maintain and easier to understand.</p> | ||||
| <h4>Conclusion</h4> | ||||
| <p>We hope that in this article we have been able to give you some idea of what | ||||
| type-traits are all about. A more complete listing of the available classes are | ||||
| in the boost documentation, along with further examples using type traits. | ||||
| Templates have enabled C++ uses to take the advantage of the code reuse that | ||||
| generic programming brings; hopefully this article has shown that generic | ||||
| programming does not have to sink to the lowest common denominator, and that | ||||
| templates can be optimal as well as generic.</p> | ||||
| <h4>Acknowledgements</h4> | ||||
| <p>The authors would like to thank Beman Dawes and Howard Hinnant for their | ||||
| helpful comments when preparing this article.</p> | ||||
| <h4>References</h4> | ||||
| <ol> | ||||
|   <li>Nathan C. Myers, C++ Report, June 1995.</li> | ||||
|   <li>The type traits library is based upon contributions by Steve Cleary, Beman | ||||
|     Dawes, Howard Hinnant and John Maddock: it can be found at www.boost.org.</li> | ||||
|   <li>A scalar type is an arithmetic type (i.e. a built-in integer or floating | ||||
|     point type), an enumeration type, a pointer, a pointer to member, or a | ||||
|     const- or volatile-qualified version of one of these types.</li> | ||||
|   <li>This quote is from Donald Knuth, ACM Computing Surveys, December 1974, pg | ||||
|     268.</li> | ||||
|   <li>The test code is available as part of the boost utility library (see | ||||
|     algo_opt_examples.cpp), the code was compiled with gcc 2.95 with all | ||||
|     optimisations turned on, tests were conducted on a 400MHz Pentium II machine | ||||
|     running Microsoft Windows 98.</li> | ||||
|   <li>John Maddock and Howard Hinnant have submitted a "compressed_pair" | ||||
|     library to Boost, which uses a technique similar to the one described here | ||||
|     to hold references. Their pair also uses type traits to determine if any of | ||||
|     the types are empty, and will derive instead of contain to conserve space -- | ||||
|     hence the name "compressed".</li> | ||||
|   <li>This is actually an issue with the C++ Core Language Working Group (issue | ||||
|     #106), submitted by Bjarne Stroustrup. The tentative resolution is to allow | ||||
|     a "reference to a reference to T" to mean the same thing as a | ||||
|     "reference to T", but only in template instantiation, in a method | ||||
|     similar to multiple cv-qualifiers.</li> | ||||
|   <li>For those of you who are wondering why this shouldn't be const-qualified, | ||||
|     remember that references are always implicitly constant (for example, you | ||||
|     can't re-assign a reference). Remember also that "const T &" | ||||
|     is something completely different. For this reason, cv-qualifiers on | ||||
|     template type arguments that are references are ignored.</li> | ||||
| </ol> | ||||
| <h2>Listing 1</h2> | ||||
| <pre>namespace detail{ | ||||
|  | ||||
| template <bool b> | ||||
| struct copier | ||||
| { | ||||
|    template<typename I1, typename I2> | ||||
|    static I2 do_copy(I1 first,  | ||||
|                      I1 last, I2 out); | ||||
| }; | ||||
|  | ||||
| template <bool b> | ||||
| template<typename I1, typename I2> | ||||
| I2 copier<b>::do_copy(I1 first,  | ||||
|                       I1 last,  | ||||
|                       I2 out) | ||||
| { | ||||
|    while(first != last) | ||||
|    { | ||||
|       *out = *first; | ||||
|       ++out; | ||||
|       ++first; | ||||
|    } | ||||
|    return out; | ||||
| } | ||||
|  | ||||
| template <> | ||||
| struct copier<true> | ||||
| { | ||||
|    template<typename I1, typename I2> | ||||
|    static I2* do_copy(I1* first, I1* last, I2* out) | ||||
|    { | ||||
|       memcpy(out, first, (last-first)*sizeof(I2)); | ||||
|       return out+(last-first); | ||||
|    } | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| template<typename I1, typename I2> | ||||
| inline I2 copy(I1 first, I1 last, I2 out) | ||||
| { | ||||
|    typedef typename  | ||||
|     boost::remove_cv< | ||||
|      typename std::iterator_traits<I1> | ||||
|       ::value_type>::type v1_t; | ||||
|  | ||||
|    typedef typename  | ||||
|     boost::remove_cv< | ||||
|      typename std::iterator_traits<I2> | ||||
|       ::value_type>::type v2_t; | ||||
|  | ||||
|    enum{ can_opt =  | ||||
|       boost::is_same<v1_t, v2_t>::value | ||||
|       && boost::is_pointer<I1>::value | ||||
|       && boost::is_pointer<I2>::value | ||||
|       && boost:: | ||||
|       has_trivial_assign<v1_t>::value  | ||||
|    }; | ||||
|  | ||||
|    return detail::copier<can_opt>:: | ||||
|       do_copy(first, last, out); | ||||
| }</pre> | ||||
| <hr> | ||||
| <p><EFBFBD> Copyright John Maddock and Steve Cleary, 2000</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
| @@ -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> | ||||
|  | ||||
| @@ -34,9 +34,9 @@ specialization or member templates, no benefit will occur from | ||||
| using call_traits: the call_traits defined types will always be | ||||
| the same as the existing practice in this case. In addition if | ||||
| only member templates and not partial template specialisation is | ||||
| support by the compiler (for example Visual C++ 6) then call_traits | ||||
| can not be used with array types (although it can be used to | ||||
| solve the reference to reference problem).</p> | ||||
| support by the compiler (for example Visual C++ 6) then | ||||
| call_traits can not be used with array types (although it can be | ||||
| used to solve the reference to reference problem).</p> | ||||
|  | ||||
| <table border="0" cellpadding="7" cellspacing="1" width="797"> | ||||
|     <tr> | ||||
| @@ -79,7 +79,8 @@ solve the reference to reference problem).</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="17%"><p align="center">const T&<br> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         T&<br> | ||||
|         (return value)</p> | ||||
|         </td> | ||||
|         <td valign="top" width="35%"><p align="center"><code>call_traits<T>::const_reference</code></p> | ||||
| @@ -91,7 +92,8 @@ solve the reference to reference problem).</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="17%"><p align="center">const T&<br> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         T&<br> | ||||
|         (function parameter)</p> | ||||
|         </td> | ||||
|         <td valign="top" width="35%"><p align="center"><code>call_traits<T>::param_type</code></p> | ||||
| @@ -332,8 +334,8 @@ possible:</p> | ||||
| <p>The following table shows the effect that call_traits has on | ||||
| various types, the table assumes that the compiler supports | ||||
| partial specialization: if it doesn't then all types behave in | ||||
| the same way as the entry for "myclass", and call_traits | ||||
| can not be used with reference or array types.</p> | ||||
| the same way as the entry for "myclass", and | ||||
| call_traits can not be used with reference or array types.</p> | ||||
|  | ||||
| <table border="0" cellpadding="7" cellspacing="1" width="766"> | ||||
|     <tr> | ||||
| @@ -388,7 +390,8 @@ can not be used with reference or array types.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">int const</p> | ||||
|         </td> | ||||
| @@ -420,7 +423,8 @@ can not be used with reference or array types.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">int&</p> | ||||
|         </td> | ||||
| @@ -432,13 +436,17 @@ can not be used with reference or array types.</p> | ||||
|         <td valign="top" width="17%" bgcolor="#C0C0C0"><p | ||||
|         align="center">const int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">const int&</p> | ||||
|         <td valign="top" width="17%"><p align="center">const | ||||
|         int&</p> | ||||
|         </td> | ||||
|         <td valign="top" width="17%"><p align="center">All | ||||
|         constant-references.</p> | ||||
| @@ -486,8 +494,8 @@ can not be used with reference or array types.</p> | ||||
|  | ||||
| <p>The following class is a trivial class that stores some type T | ||||
| by value (see the <a href="call_traits_test.cpp">call_traits_test.cpp</a> | ||||
| file), the aim is to illustrate how each of the available call_traits | ||||
| typedefs may be used:</p> | ||||
| file), the aim is to illustrate how each of the available | ||||
| call_traits typedefs may be used:</p> | ||||
|  | ||||
| <pre>template <class T> | ||||
| struct contained | ||||
| @@ -523,14 +531,14 @@ problem):</h4> | ||||
|  | ||||
| <pre>template <class Operation>  | ||||
| class binder1st :  | ||||
|    public unary_function<Operation::second_argument_type, Operation::result_type>  | ||||
|    public unary_function<typename Operation::second_argument_type, typename Operation::result_type>  | ||||
| {  | ||||
| protected:  | ||||
|    Operation op;  | ||||
|    Operation::first_argument_type value;  | ||||
|    typename Operation::first_argument_type value;  | ||||
| public:  | ||||
|    binder1st(const Operation& x, const Operation::first_argument_type& y);  | ||||
|    Operation::result_type operator()(const Operation::second_argument_type& x) const;  | ||||
|    binder1st(const Operation& x, const typename Operation::first_argument_type& y);  | ||||
|    typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const;  | ||||
| }; </pre> | ||||
|  | ||||
| <p>Now consider what happens in the relatively common case that | ||||
| @@ -541,7 +549,7 @@ reference to a reference as an argument, and that is not | ||||
| currently legal. The solution here is to modify <code>operator()</code> | ||||
| to use call_traits:</p> | ||||
|  | ||||
| <pre>Operation::result_type operator()(call_traits<Operation::second_argument_type>::param_type x) const;</pre> | ||||
| <pre>typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;</pre> | ||||
|  | ||||
| <p>Now in the case that <code>Operation::second_argument_type</code> | ||||
| is a reference type, the argument is passed as a reference, and | ||||
| @@ -575,9 +583,9 @@ std::pair< | ||||
| degraded to pointers if the deduced types are arrays, similar | ||||
| situations occur in the standard binders and adapters: in | ||||
| principle in any function that "wraps" a temporary | ||||
| whose type is deduced. Note that the function arguments to make_pair | ||||
| are not expressed in terms of call_traits: doing so would prevent | ||||
| template argument deduction from functioning.</p> | ||||
| whose type is deduced. Note that the function arguments to | ||||
| make_pair are not expressed in terms of call_traits: doing so | ||||
| would prevent template argument deduction from functioning.</p> | ||||
|  | ||||
| <h4><a name="ex4"></a>Example 4 (optimising fill):</h4> | ||||
|  | ||||
| @@ -666,10 +674,10 @@ be any worse than existing practice.</p> | ||||
| <p>Pointers follow the same rational as small built-in types.</p> | ||||
|  | ||||
| <p>For reference types the rational follows <a href="#refs">Example | ||||
| 2</a> - references to references are not allowed, so the call_traits | ||||
| members must be defined such that these problems do not occur. | ||||
| There is a proposal to modify the language such that "a | ||||
| reference to a reference is a reference" (issue #106, | ||||
| 2</a> - references to references are not allowed, so the | ||||
| call_traits members must be defined such that these problems do | ||||
| not occur. There is a proposal to modify the language such that | ||||
| "a reference to a reference is a reference" (issue #106, | ||||
| submitted by Bjarne Stroustrup), call_traits<T>::value_type | ||||
| and call_traits<T>::param_type both provide the same effect | ||||
| as that proposal, without the need for a language change (in | ||||
| @@ -687,11 +695,11 @@ struct A | ||||
|    void foo(T t); | ||||
| };</pre> | ||||
|  | ||||
| <p><font face="Times New Roman">In this case if we instantiate A<int[2]> | ||||
| then the declared type of the parameter passed to member function | ||||
| foo is int[2], but it's actual type is const int*, if we try to | ||||
| use the type T within the function body, then there is a strong | ||||
| likelyhood that our code will not compile:</font></p> | ||||
| <p><font face="Times New Roman">In this case if we instantiate | ||||
| A<int[2]> then the declared type of the parameter passed to | ||||
| member function foo is int[2], but it's actual type is const int*, | ||||
| if we try to use the type T within the function body, then there | ||||
| is a strong likelyhood that our code will not compile:</font></p> | ||||
|  | ||||
| <pre>template <class T> | ||||
| void A<T>::foo(T t) | ||||
| @@ -706,13 +714,13 @@ declared type:</p> | ||||
| <pre>template <class T> | ||||
| struct A | ||||
| { | ||||
|    void foo(call_traits<T>::value_type t); | ||||
|    void foo(typename call_traits<T>::value_type t); | ||||
| }; | ||||
|  | ||||
| template <class T> | ||||
| void A<T>::foo(call_traits<T>::value_type t) | ||||
| void A<T>::foo(typename call_traits<T>::value_type t) | ||||
| { | ||||
|    call_traits<T>::value_type dup(t); // OK even if T is an array type. | ||||
|    typename call_traits<T>::value_type dup(t); // OK even if T is an array type. | ||||
| }</pre> | ||||
|  | ||||
| <p>For value_type (return by value), again only a pointer may be | ||||
| @@ -743,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> | ||||
|  | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| #include <typeinfo> | ||||
| #include <boost/call_traits.hpp> | ||||
|  | ||||
| #include "type_traits_test.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: | ||||
| @@ -98,18 +98,18 @@ std::pair< | ||||
| using namespace std; | ||||
|  | ||||
| // | ||||
| // struct checker: | ||||
| // struct call_traits_checker: | ||||
| // verifies behaviour of contained example: | ||||
| // | ||||
| template <class T> | ||||
| struct checker | ||||
| struct call_traits_checker | ||||
| { | ||||
|    typedef typename boost::call_traits<T>::param_type param_type; | ||||
|    void operator()(param_type); | ||||
| }; | ||||
|  | ||||
| template <class T> | ||||
| void checker<T>::operator()(param_type p) | ||||
| void call_traits_checker<T>::operator()(param_type p) | ||||
| { | ||||
|    T t(p); | ||||
|    contained<T> c(t); | ||||
| @@ -117,18 +117,19 @@ void checker<T>::operator()(param_type p) | ||||
|    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 checker<T[N]> | ||||
| struct call_traits_checker<T[N]> | ||||
| { | ||||
|    typedef typename boost::call_traits<T[N]>::param_type param_type; | ||||
|    void operator()(param_type t) | ||||
| @@ -176,32 +177,32 @@ void check_make_pair(T c, U u, V v) | ||||
| } | ||||
|  | ||||
|  | ||||
| struct UDT | ||||
| struct comparible_UDT | ||||
| { | ||||
|    int i_; | ||||
|    UDT() : i_(2){} | ||||
|    bool operator == (const UDT& v){ return v.i_ == i_; } | ||||
|    comparible_UDT() : i_(2){} | ||||
|    bool operator == (const comparible_UDT& v){ return v.i_ == i_; } | ||||
| }; | ||||
|  | ||||
| int main() | ||||
| int main(int argc, char *argv[ ]) | ||||
| { | ||||
|    checker<UDT> c1; | ||||
|    UDT u; | ||||
|    call_traits_checker<comparible_UDT> c1; | ||||
|    comparible_UDT u; | ||||
|    c1(u); | ||||
|    checker<int> c2; | ||||
|    call_traits_checker<int> c2; | ||||
|    int i = 2; | ||||
|    c2(i); | ||||
|    int* pi = &i; | ||||
| #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) | ||||
|    checker<int*> c3; | ||||
| #if (defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)) && !defined(__ICL) | ||||
|    call_traits_checker<int*> c3; | ||||
|    c3(pi); | ||||
|    checker<int&> c4; | ||||
|    call_traits_checker<int&> c4; | ||||
|    c4(i); | ||||
|    checker<const int&> c5; | ||||
|    call_traits_checker<const int&> c5; | ||||
|    c5(i); | ||||
| #if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
| #if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__MWERKS__) | ||||
|    int a[2] = {1,2}; | ||||
|    checker<int[2]> c6; | ||||
|    call_traits_checker<int[2]> c6; | ||||
|    c6(a); | ||||
| #endif | ||||
| #endif | ||||
| @@ -220,10 +221,10 @@ int main() | ||||
|    typedef int& r_type; | ||||
|    typedef const r_type cr_type; | ||||
|  | ||||
|    type_test(UDT, boost::call_traits<UDT>::value_type) | ||||
|    type_test(UDT&, boost::call_traits<UDT>::reference) | ||||
|    type_test(const UDT&, boost::call_traits<UDT>::const_reference) | ||||
|    type_test(const UDT&, boost::call_traits<UDT>::param_type) | ||||
|    type_test(comparible_UDT, boost::call_traits<comparible_UDT>::value_type) | ||||
|    type_test(comparible_UDT&, boost::call_traits<comparible_UDT>::reference) | ||||
|    type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::const_reference) | ||||
|    type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::param_type) | ||||
|    type_test(int, boost::call_traits<int>::value_type) | ||||
|    type_test(int&, boost::call_traits<int>::reference) | ||||
|    type_test(const int&, boost::call_traits<int>::const_reference) | ||||
| @@ -237,7 +238,7 @@ int main() | ||||
|    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)) | ||||
| #if !(defined(__GNUC__) && (__GNUC__ < 4)) | ||||
|    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) | ||||
| @@ -271,9 +272,7 @@ int main() | ||||
|    test_count += 20; | ||||
| #endif | ||||
|  | ||||
|    std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; | ||||
|    std::cin.get(); | ||||
|    return failures; | ||||
|    return check_result(argc, argv); | ||||
| } | ||||
|  | ||||
| // | ||||
| @@ -364,3 +363,18 @@ 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
									
								
							
							
						
						
									
										31
									
								
								checked_delete_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| //  Boost checked_delete test program  ---------------------------------------// | ||||
|  | ||||
| //  (C) Copyright Beman Dawes 2001. Permission to copy, use, modify, sell | ||||
| //  and distribute this software is granted provided this copyright | ||||
| //  notice appears in all copies. This software is provided "as is" without | ||||
| //  express or implied warranty, and with no claim as to its suitability for | ||||
| //  any purpose. | ||||
|  | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  21 May 01  Initial version (Beman Dawes) | ||||
|  | ||||
| #include <boost/utility.hpp>  // for checked_delete | ||||
|  | ||||
| //  This program demonstrates compiler errors when trying to delete an | ||||
| //  incomplete type. | ||||
|  | ||||
| namespace | ||||
| { | ||||
|     class Incomplete; | ||||
| } | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     Incomplete * p; | ||||
|     boost::checked_delete(p);          // should cause compile time error | ||||
|     Incomplete ** pa; | ||||
|     boost::checked_array_delete(pa);   // should cause compile time error | ||||
|     return 0; | ||||
| }   // main | ||||
| @@ -6,14 +6,15 @@ content="text/html; charset=iso-8859-1"> | ||||
| <meta name="Template" | ||||
| content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> | ||||
| <title>Header <boost/compressed_pair.hpp></title> | ||||
| <title>Header </title> | ||||
| <boost/compressed_pair.hpp> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000" link="#0000FF" | ||||
| vlink="#800080"> | ||||
|  | ||||
| <h2><img src="../../c++boost.gif" width="276" height="86">Header | ||||
| <<a href="../../boost/detail/call_traits.hpp">boost/compressed_pair.hpp</a>></h2> | ||||
| <<a href="../../boost/detail/compressed_pair.hpp">boost/compressed_pair.hpp</a>></h2> | ||||
|  | ||||
| <p>All of the contents of <boost/compressed_pair.hpp> are | ||||
| defined inside namespace boost.</p> | ||||
| @@ -41,6 +42,8 @@ public: | ||||
| 	explicit compressed_pair(first_param_type x); | ||||
| 	explicit compressed_pair(second_param_type y); | ||||
|  | ||||
| 	compressed_pair& operator=(const compressed_pair&); | ||||
|  | ||||
| 	first_reference       first(); | ||||
| 	first_const_reference first() const; | ||||
|  | ||||
| @@ -61,17 +64,19 @@ constructor, and this constructor initialises both values in the | ||||
| pair to the passed value.</p> | ||||
|  | ||||
| <p>Note that compressed_pair can not be instantiated if either of | ||||
| the template arguments is an enumerator type, unless there is | ||||
| compiler support for boost::is_enum, or if boost::is_enum is | ||||
| specialised for the enumerator type.</p> | ||||
| 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, compressed_pair requires compiler support for partial | ||||
| specialisation of class templates - without that support | ||||
| compressed_pair behaves just like std::pair.</p> | ||||
| <p>Finally, a word of caution for Visual C++ 6 users: if either | ||||
| argument is an empty type, then assigning to that member will | ||||
| produce memory corruption, unless the empty type has a "do | ||||
| nothing" assignment operator defined. This is due to a bug | ||||
| in the way VC6 generates implicit assignment operators.</p> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <p>Revised 08 March 2000</p> | ||||
| <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 | ||||
| @@ -85,7 +90,8 @@ 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> | ||||
| </body> | ||||
|   | ||||
| @@ -14,15 +14,12 @@ | ||||
| #include <cassert> | ||||
|  | ||||
| #include <boost/compressed_pair.hpp> | ||||
| #include "type_traits_test.hpp" | ||||
| #include <boost/type_traits/type_traits_test.hpp> | ||||
| #define BOOST_INCLUDE_MAIN | ||||
| #include <boost/test/test_tools.hpp> | ||||
|  | ||||
| using namespace boost; | ||||
|  | ||||
| struct empty_POD_UDT{}; | ||||
| struct empty_UDT | ||||
| { | ||||
|   ~empty_UDT(){}; | ||||
| }; | ||||
| namespace boost { | ||||
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION | ||||
| template <> struct is_empty<empty_UDT> | ||||
| @@ -59,97 +56,345 @@ struct non_empty2 | ||||
|    { return a.i == b.i; } | ||||
| }; | ||||
|  | ||||
| int main() | ||||
| { | ||||
|    compressed_pair<int, double> cp1(1, 1.3); | ||||
|    assert(cp1.first() == 1); | ||||
|    assert(cp1.second() == 1.3); | ||||
|    compressed_pair<int, double> cp1b(2, 2.3); | ||||
|    assert(cp1b.first() == 2); | ||||
|    assert(cp1b.second() == 2.3); | ||||
|    swap(cp1, cp1b); | ||||
|    assert(cp1b.first() == 1); | ||||
|    assert(cp1b.second() == 1.3); | ||||
|    assert(cp1.first() == 2); | ||||
|    assert(cp1.second() == 2.3); | ||||
|    compressed_pair<non_empty1, non_empty2> cp1c(non_empty1(9)); | ||||
|    assert(cp1c.second() == non_empty2()); | ||||
|    assert(cp1c.first() == non_empty1(9)); | ||||
|    compressed_pair<non_empty1, non_empty2> cp1d(non_empty2(9)); | ||||
|    assert(cp1d.second() == non_empty2(9)); | ||||
|    assert(cp1d.first() == non_empty1()); | ||||
|    compressed_pair<empty_UDT, int> cp2(2); | ||||
|    assert(cp2.second() == 2); | ||||
|    compressed_pair<int, empty_UDT> cp3(1); | ||||
|    assert(cp3.first() ==1); | ||||
|    compressed_pair<empty_UDT, empty_UDT> cp4; | ||||
|    compressed_pair<empty_UDT, empty_POD_UDT> cp5; | ||||
|    compressed_pair<int, empty_UDT> cp9(empty_UDT()); | ||||
|    compressed_pair<int, empty_UDT> cp10(1); | ||||
|    assert(cp10.first() == 1); | ||||
| #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
|    int i = 0; | ||||
|    compressed_pair<int&, int&> cp6(i,i); | ||||
|    assert(cp6.first() == i); | ||||
|    assert(cp6.second() == i); | ||||
|    assert(&cp6.first() == &i); | ||||
|    assert(&cp6.second() == &i); | ||||
|    compressed_pair<int, double[2]> cp7; | ||||
|    cp7.first(); | ||||
|    double* pd = cp7.second(); | ||||
| #ifdef __GNUC__ | ||||
| using std::swap; | ||||
| #endif | ||||
|    value_test(true, (sizeof(compressed_pair<empty_UDT, int>) < sizeof(std::pair<empty_UDT, int>))) | ||||
|    value_test(true, (sizeof(compressed_pair<int, empty_UDT>) < sizeof(std::pair<int, empty_UDT>))) | ||||
|    value_test(true, (sizeof(compressed_pair<empty_UDT, empty_UDT>) < sizeof(std::pair<empty_UDT, empty_UDT>))) | ||||
|    value_test(true, (sizeof(compressed_pair<empty_UDT, empty_POD_UDT>) < sizeof(std::pair<empty_UDT, empty_POD_UDT>))) | ||||
|    value_test(true, (sizeof(compressed_pair<empty_UDT, compressed_pair<empty_POD_UDT, int> >) < sizeof(std::pair<empty_UDT, std::pair<empty_POD_UDT, int> >))) | ||||
|  | ||||
|    std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; | ||||
|    std::cin.get(); | ||||
|    return failures; | ||||
| 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); | ||||
| } | ||||
|  | ||||
| // | ||||
| // instanciate some compressed pairs: | ||||
| #ifdef __MWERKS__ | ||||
| template class compressed_pair<int, double>; | ||||
| template class compressed_pair<int, int>; | ||||
| template class compressed_pair<empty_UDT, int>; | ||||
| template class compressed_pair<int, empty_UDT>; | ||||
| template class compressed_pair<empty_UDT, empty_UDT>; | ||||
| template class compressed_pair<empty_UDT, empty_POD_UDT>; | ||||
| #else | ||||
| template class boost::compressed_pair<int, double>; | ||||
| template class boost::compressed_pair<int, int>; | ||||
| template class boost::compressed_pair<empty_UDT, int>; | ||||
| template class boost::compressed_pair<int, empty_UDT>; | ||||
| template class boost::compressed_pair<empty_UDT, empty_UDT>; | ||||
| template class boost::compressed_pair<empty_UDT, empty_POD_UDT>; | ||||
| #endif | ||||
| // 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 | ||||
| #ifndef __MWERKS__ | ||||
|    // first param construct: | ||||
|    boost::compressed_pair<T1,T2> cp2(p1); | ||||
|    cp2.second() = p2; | ||||
|    BOOST_TEST(cp2.first() == p1); | ||||
|    BOOST_TEST(cp2.second() == p2); | ||||
| #endif | ||||
| } | ||||
| // | ||||
| // now some for which only a few specific members can be instantiated, | ||||
| // first references: | ||||
| template double& compressed_pair<double, int&>::first(); | ||||
| template int& compressed_pair<double, int&>::second(); | ||||
| #if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 95)) | ||||
| template compressed_pair<double, int&>::compressed_pair(int&); | ||||
| #endif | ||||
| template compressed_pair<double, int&>::compressed_pair(call_traits<double>::param_type,int&); | ||||
| // supplimentary tests for case where second arg only is a reference type: | ||||
| // | ||||
| // and then arrays: | ||||
| #ifndef __BORLANDC__ | ||||
| template call_traits<int[2]>::reference compressed_pair<double, int[2]>::second(); | ||||
| 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 | ||||
| template call_traits<double>::reference compressed_pair<double, int[2]>::first(); | ||||
| #if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 95)) | ||||
| template compressed_pair<double, int[2]>::compressed_pair(call_traits<double>::param_type); | ||||
| #endif | ||||
| template compressed_pair<double, int[2]>::compressed_pair(); | ||||
| #endif // __MWERKS__ | ||||
| #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
| } | ||||
|  | ||||
| // | ||||
| // tests for where one or the other parameter is an array: | ||||
| // | ||||
| template <class T1, class T2> | ||||
| struct compressed_pair_array1_tester | ||||
| { | ||||
|    // define the types we need: | ||||
|    typedef T1                                                 first_type; | ||||
|    typedef T2                                                 second_type; | ||||
|    typedef typename call_traits<first_type>::param_type       first_param_type; | ||||
|    typedef typename call_traits<second_type>::param_type      second_param_type; | ||||
|    // define our test proc: | ||||
|    static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4); | ||||
| }; | ||||
|  | ||||
| template <class T1, class T2> | ||||
| void compressed_pair_array1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4) | ||||
| { | ||||
|   // default construct: | ||||
|    boost::compressed_pair<T1,T2> cp1; | ||||
|    // second param construct: | ||||
|    boost::compressed_pair<T1,T2> cp3(p2); | ||||
|    cp3.first()[0] = p1[0]; | ||||
|    BOOST_TEST(cp3.second() == p2); | ||||
|    BOOST_TEST(cp3.first()[0] == p1[0]); | ||||
|    // check const members: | ||||
|    const boost::compressed_pair<T1,T2>& cpr1 = cp3; | ||||
|    BOOST_TEST(cpr1.first()[0] == p1[0]); | ||||
|    BOOST_TEST(cpr1.second() == p2); | ||||
|  | ||||
|    BOOST_TEST(sizeof(T1) == sizeof(cp1.first())); | ||||
| } | ||||
|  | ||||
| template <class T1, class T2> | ||||
| struct compressed_pair_array2_tester | ||||
| { | ||||
|    // define the types we need: | ||||
|    typedef T1                                                 first_type; | ||||
|    typedef T2                                                 second_type; | ||||
|    typedef typename call_traits<first_type>::param_type       first_param_type; | ||||
|    typedef typename call_traits<second_type>::param_type      second_param_type; | ||||
|    // define our test proc: | ||||
|    static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4); | ||||
| }; | ||||
|  | ||||
| template <class T1, class T2> | ||||
| void compressed_pair_array2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4) | ||||
| { | ||||
|    // default construct: | ||||
|    boost::compressed_pair<T1,T2> cp1; | ||||
|    // first param construct: | ||||
|    boost::compressed_pair<T1,T2> cp2(p1); | ||||
|    cp2.second()[0] = p2[0]; | ||||
|    BOOST_TEST(cp2.first() == p1); | ||||
|    BOOST_TEST(cp2.second()[0] == p2[0]); | ||||
|    // check const members: | ||||
|    const boost::compressed_pair<T1,T2>& cpr1 = cp2; | ||||
|    BOOST_TEST(cpr1.first() == p1); | ||||
|    BOOST_TEST(cpr1.second()[0] == p2[0]); | ||||
|  | ||||
|    BOOST_TEST(sizeof(T2) == sizeof(cp1.second())); | ||||
| } | ||||
|  | ||||
| template <class T1, class T2> | ||||
| struct compressed_pair_array_tester | ||||
| { | ||||
|    // define the types we need: | ||||
|    typedef T1                                                 first_type; | ||||
|    typedef T2                                                 second_type; | ||||
|    typedef typename call_traits<first_type>::param_type       first_param_type; | ||||
|    typedef typename call_traits<second_type>::param_type      second_param_type; | ||||
|    // define our test proc: | ||||
|    static void test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4); | ||||
| }; | ||||
|  | ||||
| template <class T1, class T2> | ||||
| void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4) | ||||
| { | ||||
|    // default construct: | ||||
|    boost::compressed_pair<T1,T2> cp1; | ||||
|    cp1.first()[0] = p1[0]; | ||||
|    cp1.second()[0] = p2[0]; | ||||
|    BOOST_TEST(cp1.first()[0] == p1[0]); | ||||
|    BOOST_TEST(cp1.second()[0] == p2[0]); | ||||
|    // check const members: | ||||
|    const boost::compressed_pair<T1,T2>& cpr1 = cp1; | ||||
|    BOOST_TEST(cpr1.first()[0] == p1[0]); | ||||
|    BOOST_TEST(cpr1.second()[0] == p2[0]); | ||||
|  | ||||
|    BOOST_TEST(sizeof(T1) == sizeof(cp1.first())); | ||||
|    BOOST_TEST(sizeof(T2) == sizeof(cp1.second())); | ||||
| } | ||||
|  | ||||
| int test_main(int argc, char *argv[ ]) | ||||
| { | ||||
|    // declare some variables to pass to the tester: | ||||
|    non_empty1 ne1(2); | ||||
|    non_empty1 ne2(3); | ||||
|    non_empty2 ne3(4); | ||||
|    non_empty2 ne4(5); | ||||
|    empty_POD_UDT  e1; | ||||
|    empty_UDT      e2; | ||||
|  | ||||
|    // T1 != T2, both non-empty | ||||
|    compressed_pair_tester<non_empty1,non_empty2>::test(ne1, ne3, ne2, ne4); | ||||
|    // T1 != T2, T2 empty | ||||
|    compressed_pair_tester<non_empty1,empty_POD_UDT>::test(ne1, e1, ne2, e1); | ||||
|    // T1 != T2, T1 empty | ||||
|    compressed_pair_tester<empty_POD_UDT,non_empty2>::test(e1, ne3, e1, ne4); | ||||
|    // T1 != T2, both empty | ||||
|    compressed_pair_tester<empty_POD_UDT,empty_UDT>::test(e1, e2, e1, e2); | ||||
|    // T1 == T2, both non-empty | ||||
|    compressed_pair_tester<non_empty1,non_empty1>::test(ne1, ne1, ne2, ne2); | ||||
|    // T1 == T2, both empty | ||||
|    compressed_pair_tester<empty_UDT,empty_UDT>::test(e2, e2, e2, e2); | ||||
|  | ||||
|  | ||||
|    // test references: | ||||
|  | ||||
|    // T1 != T2, both non-empty | ||||
|    compressed_pair_reference_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4); | ||||
|    compressed_pair_reference_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4); | ||||
|    compressed_pair_reference1_tester<non_empty1&,non_empty2>::test(ne1, ne3, ne2, ne4); | ||||
|    compressed_pair_reference2_tester<non_empty1,non_empty2&>::test(ne1, ne3, ne2, ne4); | ||||
|    // T1 != T2, T2 empty | ||||
|    compressed_pair_reference_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1); | ||||
|    compressed_pair_reference1_tester<non_empty1&,empty_POD_UDT>::test(ne1, e1, ne2, e1); | ||||
|    // T1 != T2, T1 empty | ||||
|    compressed_pair_reference_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4); | ||||
|    compressed_pair_reference2_tester<empty_POD_UDT,non_empty2&>::test(e1, ne3, e1, ne4); | ||||
|    // T1 == T2, both non-empty | ||||
|    compressed_pair_reference_tester<non_empty1&,non_empty1&>::test(ne1, ne1, ne2, ne2); | ||||
|  | ||||
|    // tests arrays: | ||||
|    non_empty1 nea1[2]; | ||||
|    non_empty1 nea2[2]; | ||||
|    non_empty2 nea3[2]; | ||||
|    non_empty2 nea4[2]; | ||||
|    nea1[0] = non_empty1(5); | ||||
|    nea2[0] = non_empty1(6); | ||||
|    nea3[0] = non_empty2(7); | ||||
|    nea4[0] = non_empty2(8); | ||||
|     | ||||
|    // T1 != T2, both non-empty | ||||
|    compressed_pair_array1_tester<non_empty1[2],non_empty2>::test(nea1, ne3, nea2, ne4); | ||||
|    compressed_pair_array2_tester<non_empty1,non_empty2[2]>::test(ne1, nea3, ne2, nea4); | ||||
|    compressed_pair_array_tester<non_empty1[2],non_empty2[2]>::test(nea1, nea3, nea2, nea4); | ||||
|    // T1 != T2, T2 empty | ||||
|    compressed_pair_array1_tester<non_empty1[2],empty_POD_UDT>::test(nea1, e1, nea2, e1); | ||||
|    // T1 != T2, T1 empty | ||||
|    compressed_pair_array2_tester<empty_POD_UDT,non_empty2[2]>::test(e1, nea3, e1, nea4); | ||||
|    // T1 == T2, both non-empty | ||||
|    compressed_pair_array_tester<non_empty1[2],non_empty1[2]>::test(nea1, nea1, nea2, nea2); | ||||
|    return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| unsigned int expected_failures = 0; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										325
									
								
								counting_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								counting_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>Counting Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" | ||||
| align="center" width="277" height="86"> | ||||
|  | ||||
| <h1>Counting Iterator Adaptor</h1> | ||||
|  | ||||
| Defined in header | ||||
| <a href="../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a> | ||||
|  | ||||
| <p> | ||||
| How would you fill up a vector with the numbers zero | ||||
| through one hundred using <a | ||||
| href="http://www.sgi.com/tech/stl/copy.html"><tt>std::copy()</tt></a>? The | ||||
| only iterator operation missing from builtin integer types is an | ||||
| <tt>operator*()</tt> that returns the current | ||||
| value of the integer.  The counting iterator adaptor adds this crucial piece of | ||||
| functionality to whatever type it wraps. One can use the | ||||
| counting iterator adaptor not only with integer types, but with any | ||||
| type that is <tt>Incrementable</tt> (see type requirements <a href="#requirements">below</a>).  The | ||||
| following <b>pseudo-code</b> shows the general idea of how the | ||||
| counting iterator is implemented. | ||||
| </p> | ||||
|  | ||||
| <pre> | ||||
|   // inside a hypothetical counting_iterator class... | ||||
|   typedef Incrementable value_type; | ||||
|   value_type counting_iterator::operator*() const { | ||||
|     return this->base; // no dereference! | ||||
|   } | ||||
| </pre> | ||||
|  | ||||
| All of the other operators of the counting iterator behave in the same | ||||
| fashion as the <tt>Incrementable</tt> base type. | ||||
|  | ||||
| <h2>Synopsis</h2> | ||||
|  | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class Incrementable> | ||||
|   struct <a href="#counting_iterator_traits">counting_iterator_traits</a>; | ||||
|  | ||||
|   template <class Incrementable> | ||||
|   struct <a href="#counting_iterator_generator">counting_iterator_generator</a>; | ||||
|  | ||||
|   template <class Incrementable> | ||||
|   typename counting_iterator_generator<Incrementable>::type | ||||
|   <a href="#make_counting_iterator">make_counting_iterator</a>(Incrementable x); | ||||
| } | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <h2><a name="counting_iterator_generator">The Counting Iterator Type | ||||
| Generator</a></h2> | ||||
|  | ||||
| The class template <tt>counting_iterator_generator<Incrementable></tt> is a <a href="../../more/generic_programming.html#type_generator">type generator</a> for counting iterators. | ||||
|  | ||||
| <pre> | ||||
| template <class Incrementable> | ||||
| class counting_iterator_generator | ||||
| { | ||||
| public: | ||||
|     typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...> type; | ||||
| }; | ||||
| </pre> | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In this example we use the counting iterator generator to create a | ||||
| counting iterator, and count from zero to four. | ||||
|  | ||||
| <pre> | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <boost/counting_iterator.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   // Example of using counting_iterator_generator | ||||
|   std::cout << "counting from 0 to 4:" << std::endl; | ||||
|   boost::counting_iterator_generator<int>::type first(0), last(4); | ||||
|   std::copy(first, last, std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // to be continued... | ||||
| </pre> | ||||
| The output from this part is: | ||||
| <pre> | ||||
| counting from 0 to 4: | ||||
| 0 1 2 3  | ||||
| </pre> | ||||
|  | ||||
| <h3>Template Parameters</h3> | ||||
|  | ||||
| <Table border> | ||||
| <TR> | ||||
| <TH>Parameter</TH><TH>Description</TH> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Incrementable</tt></TD> | ||||
| <TD>The type being wrapped by the adaptor.</TD> | ||||
| </TR> | ||||
|  | ||||
| </Table> | ||||
|  | ||||
| <h3>Model of</h3> | ||||
|  | ||||
| If the <tt>Incrementable</tt> type has all of the functionality of a | ||||
| <a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> except the <tt>operator*()</tt>, then the counting | ||||
| iterator will be a model of <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a>. If the <tt>Incrementable</tt> type has less | ||||
| functionality, then the counting iterator will have correspondingly | ||||
| less functionality. | ||||
|  | ||||
| <h3><a name="requirements">Type Requirements</a></h3> | ||||
|  | ||||
| The <tt>Incrementable</tt> type must be <a | ||||
| href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default | ||||
| Constructible</a>, <a href="./CopyConstructible.html">Copy | ||||
| Constructible</a>, and <a href="./Assignable.html">Assignable</a>. | ||||
| Also, the <tt>Incrementable</tt> type must provide access to an | ||||
| associated <tt>difference_type</tt> and <tt>iterator_category</tt> | ||||
| through the <a | ||||
| href="#counting_iterator_traits"><tt>counting_iterator_traits</tt></a> | ||||
| class. | ||||
|  | ||||
| <p> | ||||
| Furthermore, if you wish to create a counting iterator that is a <a | ||||
| href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward | ||||
| Iterator</a>, then the following expressions must be valid: | ||||
| <pre> | ||||
| Incrementable i, j; | ||||
| ++i         // pre-increment | ||||
| i == j      // operator equal | ||||
| </pre> | ||||
| If you wish to create a counting iterator that is a <a | ||||
| href="http://www.sgi.com/tech/stl/BidirectionalIterator.html"> | ||||
| Bidirectional Iterator</a>, then pre-decrement is also required: | ||||
| <pre> | ||||
| --i | ||||
| </pre> | ||||
| If you wish to create a counting iterator that is a <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> Random | ||||
| Access Iterator</a>, then these additional expressions are also required: | ||||
| <pre> | ||||
| <a href="#counting_iterator_traits">counting_iterator_traits</a><Incrementable>::difference_type n; | ||||
| i += n | ||||
| n = i - j | ||||
| i < j | ||||
| </pre> | ||||
|  | ||||
|  | ||||
|  | ||||
| <h3>Members</h3> | ||||
|  | ||||
| The counting iterator type implements the member functions and | ||||
| operators required of the <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> concept. In addition it has the following | ||||
| constructor: | ||||
|  | ||||
| <pre> | ||||
| counting_iterator_generator::type(const Incrementable& i) | ||||
| </pre> | ||||
|  | ||||
| <p> | ||||
| <hr> | ||||
| <p> | ||||
|  | ||||
|  | ||||
| <h2><a name="make_counting_iterator">The Counting Iterator Object Generator</a></h2> | ||||
|  | ||||
| <pre> | ||||
| template <class Incrementable> | ||||
| typename counting_iterator_generator<Incrementable>::type | ||||
| make_counting_iterator(Incrementable base); | ||||
| </pre> | ||||
|  | ||||
| An <a href="../../more/generic_programming.html#object_generator">object | ||||
| generator</a> function that provides a convenient way to create counting | ||||
| iterators.<p> | ||||
|  | ||||
|  | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In this example we count from negative five to positive five, this | ||||
| time using the <tt>make_counting_iterator()</tt> function to save some | ||||
| typing. | ||||
|  | ||||
| <pre> | ||||
|   // continuing from previous example... | ||||
|  | ||||
|   std::cout << "counting from -5 to 4:" << std::endl; | ||||
|   std::copy(boost::make_counting_iterator(-5), | ||||
| 	    boost::make_counting_iterator(5), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // to be continued... | ||||
| </pre> | ||||
| The output from this part is: | ||||
| <pre> | ||||
| counting from -5 to 4: | ||||
| -5 -4 -3 -2 -1 0 1 2 3 4  | ||||
| </pre> | ||||
|  | ||||
| In the next example we create an array of numbers, and then create a | ||||
| second array of pointers, where each pointer is the address of a | ||||
| number in the first array. The counting iterator makes it easy to do | ||||
| this since dereferencing a counting iterator that is wrapping an | ||||
| iterator over the array of numbers just returns a pointer to the | ||||
| current location in the array. We then use the <a | ||||
| href="./indirect_iterator.htm">indirect iterator adaptor</a> to print | ||||
| out the number in the array by accessing the numbers through the array | ||||
| of pointers. | ||||
|  | ||||
| <pre> | ||||
|   // continuing from previous example... | ||||
|  | ||||
|   const int N = 7; | ||||
|   std::vector<int> numbers; | ||||
|   // Fill "numbers" array with [0,N) | ||||
|   std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N), | ||||
| 	    std::back_inserter(numbers)); | ||||
|  | ||||
|   std::vector<std::vector<int>::iterator> pointers; | ||||
|  | ||||
|   // Use counting iterator to fill in the array of pointers. | ||||
|   std::copy(boost::make_counting_iterator(numbers.begin()), | ||||
| 	    boost::make_counting_iterator(numbers.end()), | ||||
| 	    std::back_inserter(pointers)); | ||||
|  | ||||
|   // Use indirect iterator to print out numbers by accessing | ||||
|   // them through the array of pointers. | ||||
|   std::cout << "indirectly printing out the numbers from 0 to "  | ||||
| 	    << N << std::endl; | ||||
|   std::copy(boost::make_indirect_iterator(pointers.begin()), | ||||
| 	    boost::make_indirect_iterator(pointers.end()), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| indirectly printing out the numbers from 0 to 7 | ||||
| 0 1 2 3 4 5 6  | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <h2><a name="counting_iterator_traits">Counting Iterator Traits</a></h2> | ||||
|  | ||||
| The counting iterator adaptor needs to determine the appropriate | ||||
| <tt>difference_type</tt> and <tt>iterator_category</tt> to use based on the | ||||
| <tt>Incrementable</tt> type supplied by the user.  The | ||||
| <tt>counting_iterator_traits</tt> class provides these types.  If the | ||||
| <tt>Incrementable</tt> type is an integral type or an iterator, these types | ||||
| will be correctly deduced by the <tt>counting_iterator_traits</tt> provided by | ||||
| the library. Otherwise, the user must specialize | ||||
| <tt>counting_iterator_traits</tt> for her type or add nested typedefs to | ||||
| her type to fulfill the needs of | ||||
| <a href="http://www.sgi.com/tech/stl/iterator_traits.html"> | ||||
| <tt>std::iterator_traits</tt></a>. | ||||
|  | ||||
| <p>The following pseudocode describes how the <tt>counting_iterator_traits</tt> are determined: | ||||
|  | ||||
| <pre> | ||||
| template <class Incrementable> | ||||
| struct counting_iterator_traits | ||||
| { | ||||
|   if (numeric_limits<Incrementable>::is_specialized) { | ||||
|     if (!numeric_limits<Incrementable>::is_integer) | ||||
|        COMPILE_TIME_ERROR; | ||||
|  | ||||
|     if (!numeric_limits<Incrementable>::is_bounded | ||||
|         && numeric_limits<Incrementable>::is_signed) { | ||||
|         typedef Incrementable difference_type; | ||||
|     } | ||||
|     else if (numeric_limits<Incrementable>::is_integral) { | ||||
|         typedef <i>next-larger-signed-type-or-intmax_t</i> difference_type; | ||||
|     } | ||||
|     typedef std::random_access_iterator_tag iterator_category;    | ||||
|   } else { | ||||
|     typedef std::iterator_traits<Incrementable>::difference_type difference_type; | ||||
|     typedef std::iterator_traits<Incrementable>::iterator_category iterator_category; | ||||
|   } | ||||
| }; | ||||
| </pre> | ||||
|  | ||||
| <p>The italicized sections above are implementation details, but it is important | ||||
| to know that the <tt>difference_type</tt> for integral types is selected so that | ||||
| it can always represent the difference between two values if such a built-in | ||||
| integer exists. On platforms with a working <tt>std::numeric_limits</tt> | ||||
| implementation, the <tt>difference_type</tt> for any variable-length signed | ||||
| integer type <tt>T</tt> is <tt>T</tt> itself. | ||||
|  | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p> | ||||
| <p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use, | ||||
| modify, sell and distribute this document is granted provided this copyright | ||||
| notice appears in all copies. This document is provided "as is" | ||||
| without express or implied warranty, and with no claim as to its suitability for | ||||
| any purpose.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
| <!--  LocalWords:  html charset alt gif hpp incrementable const namespace htm | ||||
|  --> | ||||
| <!--  LocalWords:  struct  typename iostream int Siek CopyConstructible pre | ||||
|  --> | ||||
|  | ||||
							
								
								
									
										53
									
								
								counting_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								counting_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears | ||||
| // in all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <vector> | ||||
| #include <boost/counting_iterator.hpp> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   // Example of using counting_iterator_generator | ||||
|   std::cout << "counting from 0 to 4:" << std::endl; | ||||
|   boost::counting_iterator_generator<int>::type first(0), last(4); | ||||
|   std::copy(first, last, std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // Example of using make_counting_iterator() | ||||
|   std::cout << "counting from -5 to 4:" << std::endl; | ||||
|   std::copy(boost::make_counting_iterator(-5), | ||||
| 	    boost::make_counting_iterator(5), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // Example of using counting iterator to create an array of pointers. | ||||
|   const int N = 7; | ||||
|   std::vector<int> numbers; | ||||
|   // Fill "numbers" array with [0,N) | ||||
|   std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N), | ||||
| 	    std::back_inserter(numbers)); | ||||
|  | ||||
|   std::vector<std::vector<int>::iterator> pointers; | ||||
|  | ||||
|   // Use counting iterator to fill in the array of pointers. | ||||
|   std::copy(boost::make_counting_iterator(numbers.begin()), | ||||
| 	    boost::make_counting_iterator(numbers.end()), | ||||
| 	    std::back_inserter(pointers)); | ||||
|  | ||||
|   // Use indirect iterator to print out numbers by accessing | ||||
|   // them through the array of pointers. | ||||
|   std::cout << "indirectly printing out the numbers from 0 to "  | ||||
| 	    << N << std::endl; | ||||
|   std::copy(boost::make_indirect_iterator(pointers.begin()), | ||||
| 	    boost::make_indirect_iterator(pointers.end()), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										263
									
								
								counting_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								counting_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| // (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears in | ||||
| // all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
| // | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
| // | ||||
| // Revision History | ||||
| // 16 Feb 2001  Added a missing const. Made the tests run (somewhat) with | ||||
| //              plain MSVC again. (David Abrahams) | ||||
| // 11 Feb 2001  #if 0'd out use of counting_iterator on non-numeric types in | ||||
| //              MSVC without STLport, so that the other tests may proceed | ||||
| //              (David Abrahams) | ||||
| // 04 Feb 2001  Added use of iterator_tests.hpp (David Abrahams) | ||||
| // 28 Jan 2001  Removed not_an_iterator detritus (David Abrahams) | ||||
| // 24 Jan 2001  Initial revision (David Abrahams) | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #ifdef BOOST_MSVC | ||||
| # pragma warning(disable:4786) // identifier truncated in debug info | ||||
| #endif | ||||
|  | ||||
| #include <boost/pending/iterator_tests.hpp> | ||||
| #include <boost/counting_iterator.hpp> | ||||
| #include <boost/detail/iterator.hpp> | ||||
| #include <iostream> | ||||
| #include <climits> | ||||
| #include <iterator> | ||||
| #include <stdlib.h> | ||||
| #include <boost/utility.hpp> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| #include <cassert> | ||||
| #ifndef BOOST_NO_LIMITS | ||||
| # include <limits> | ||||
| #endif | ||||
| #ifndef BOOST_NO_SLIST | ||||
| # include <slist> | ||||
| #endif | ||||
|  | ||||
| template <class T> struct is_numeric | ||||
| { | ||||
|     enum { value =  | ||||
| #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | ||||
|         std::numeric_limits<T>::is_specialized | ||||
| #else | ||||
|         // Causes warnings with GCC, but how else can I detect numeric types at | ||||
|         // compile-time? | ||||
|         (boost::is_convertible<int,T>::value && | ||||
|          boost::is_convertible<T,int>::value) | ||||
| #endif | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| // Special tests for RandomAccess CountingIterators. | ||||
| template <class CountingIterator> | ||||
| void category_test( | ||||
|     CountingIterator start, | ||||
|     CountingIterator finish, | ||||
|     std::random_access_iterator_tag) | ||||
| { | ||||
|     typedef typename | ||||
|         boost::detail::iterator_traits<CountingIterator>::difference_type | ||||
|         difference_type; | ||||
|     difference_type distance = boost::detail::distance(start, finish); | ||||
|  | ||||
|     // Pick a random position internal to the range | ||||
|     difference_type offset = (unsigned)rand() % distance; | ||||
|     assert(offset >= 0); | ||||
|     CountingIterator internal = start; | ||||
|     std::advance(internal, offset); | ||||
|  | ||||
|     // Try some binary searches on the range to show that it's ordered | ||||
|     assert(std::binary_search(start, finish, *internal)); | ||||
|     CountingIterator x,y; | ||||
|     boost::tie(x,y) = std::equal_range(start, finish, *internal); | ||||
|     assert(boost::detail::distance(x, y) == 1); | ||||
|  | ||||
|     // Show that values outside the range can't be found | ||||
|     assert(!std::binary_search(start, boost::prior(finish), *finish)); | ||||
|  | ||||
|     // Do the generic random_access_iterator_test | ||||
|     typedef typename CountingIterator::value_type value_type; | ||||
|     std::vector<value_type> v; | ||||
|     for (value_type z = *start; z != *finish; ++z) | ||||
|         v.push_back(z); | ||||
|     if (v.size() >= 2) | ||||
|     { | ||||
|         // Note that this test requires a that the first argument is | ||||
|         // dereferenceable /and/ a valid iterator prior to the first argument | ||||
|         boost::random_access_iterator_test(start + 1, v.size() - 1, v.begin() + 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Special tests for bidirectional CountingIterators | ||||
| template <class CountingIterator> | ||||
| void category_test(CountingIterator start, CountingIterator finish, std::bidirectional_iterator_tag) | ||||
| { | ||||
|     if (finish != start | ||||
|         && finish != boost::next(start) | ||||
|         && finish != boost::next(boost::next(start))) | ||||
|     { | ||||
|         // Note that this test requires a that the first argument is | ||||
|         // dereferenceable /and/ a valid iterator prior to the first argument | ||||
|         boost::bidirectional_iterator_test(boost::next(start), boost::next(*start), boost::next(boost::next(*start))); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <class CountingIterator> | ||||
| void category_test(CountingIterator start, CountingIterator finish, std::forward_iterator_tag) | ||||
| { | ||||
|     if (finish != start && finish != boost::next(start)) | ||||
|         boost::forward_iterator_test(start, *start, boost::next(*start)); | ||||
| } | ||||
|  | ||||
| template <class CountingIterator> | ||||
| void test_aux(CountingIterator start, CountingIterator finish) | ||||
| { | ||||
|     typedef typename CountingIterator::iterator_category category; | ||||
|     typedef typename CountingIterator::value_type value_type; | ||||
|  | ||||
|     // If it's a RandomAccessIterator we can do a few delicate tests | ||||
|     category_test(start, finish, category()); | ||||
|      | ||||
|     // Okay, brute force... | ||||
|     for (CountingIterator p = start; p != finish && boost::next(p) != finish; ++p) | ||||
|     { | ||||
|         assert(boost::next(*p) == *boost::next(p)); | ||||
|     } | ||||
|  | ||||
|     // prove that a reference can be formed to these values | ||||
|     typedef typename CountingIterator::value_type value; | ||||
|     const value* q = &*start; | ||||
|     (void)q; // suppress unused variable warning | ||||
| } | ||||
|  | ||||
| template <class Incrementable> | ||||
| void test(Incrementable start, Incrementable finish) | ||||
| { | ||||
|     test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish)); | ||||
| } | ||||
|  | ||||
| template <class Integer> | ||||
| void test_integer(Integer* = 0) // default arg works around MSVC bug | ||||
| { | ||||
|     Integer start = 0; | ||||
|     Integer finish = 120; | ||||
|     test(start, finish); | ||||
| } | ||||
|  | ||||
| template <class Container> | ||||
| void test_container(Container* = 0)  // default arg works around MSVC bug | ||||
| { | ||||
|     Container c(1 + (unsigned)rand() % 1673); | ||||
|  | ||||
|     const typename Container::iterator start = c.begin(); | ||||
|      | ||||
|     // back off by 1 to leave room for dereferenceable value at the end | ||||
|     typename Container::iterator finish = start; | ||||
|     std::advance(finish, c.size() - 1); | ||||
|      | ||||
|     test(start, finish); | ||||
|  | ||||
|     typedef typename Container::const_iterator const_iterator; | ||||
|     test(const_iterator(start), const_iterator(finish)); | ||||
| } | ||||
|  | ||||
| class my_int1 { | ||||
| public: | ||||
|   my_int1() { } | ||||
|   my_int1(int x) : m_int(x) { } | ||||
|   my_int1& operator++() { ++m_int; return *this; } | ||||
|   bool operator==(const my_int1& x) const { return m_int == x.m_int; } | ||||
| private: | ||||
|   int m_int; | ||||
| }; | ||||
|  | ||||
| namespace boost { | ||||
|   template <> | ||||
|   struct counting_iterator_traits<my_int1> { | ||||
|     typedef std::ptrdiff_t difference_type; | ||||
|     typedef std::forward_iterator_tag iterator_category; | ||||
|   }; | ||||
| } | ||||
|  | ||||
| class my_int2 { | ||||
| public: | ||||
|   typedef void value_type; | ||||
|   typedef void pointer; | ||||
|   typedef void reference; | ||||
|   typedef std::ptrdiff_t difference_type; | ||||
|   typedef std::bidirectional_iterator_tag iterator_category; | ||||
|  | ||||
|   my_int2() { } | ||||
|   my_int2(int x) : m_int(x) { } | ||||
|   my_int2& operator++() { ++m_int; return *this; } | ||||
|   my_int2& operator--() { --m_int; return *this; } | ||||
|   bool operator==(const my_int2& x) const { return m_int == x.m_int; } | ||||
| private: | ||||
|   int m_int; | ||||
| }; | ||||
|  | ||||
| class my_int3 { | ||||
| public: | ||||
|   typedef void value_type; | ||||
|   typedef void pointer; | ||||
|   typedef void reference; | ||||
|   typedef std::ptrdiff_t difference_type; | ||||
|   typedef std::random_access_iterator_tag iterator_category; | ||||
|  | ||||
|   my_int3() { } | ||||
|   my_int3(int x) : m_int(x) { } | ||||
|   my_int3& operator++() { ++m_int; return *this; } | ||||
|   my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; } | ||||
|   std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; } | ||||
|   my_int3& operator--() { --m_int; return *this; } | ||||
|   bool operator==(const my_int3& x) const { return m_int == x.m_int; } | ||||
|   bool operator!=(const my_int3& x) const { return m_int != x.m_int; } | ||||
|   bool operator<(const my_int3& x) const { return m_int < x.m_int; } | ||||
| private: | ||||
|   int m_int; | ||||
| }; | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     // Test the built-in integer types. | ||||
|     test_integer<char>(); | ||||
|     test_integer<unsigned char>(); | ||||
|     test_integer<signed char>(); | ||||
|     test_integer<wchar_t>(); | ||||
|     test_integer<short>(); | ||||
|     test_integer<unsigned short>(); | ||||
|     test_integer<int>(); | ||||
|     test_integer<unsigned int>(); | ||||
|     test_integer<long>(); | ||||
|     test_integer<unsigned long>(); | ||||
| #if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX) | ||||
|     test_integer<long long>(); | ||||
|     test_integer<unsigned long long>(); | ||||
| #endif | ||||
|  | ||||
|    // wrapping an iterator or non-built-in integer type causes an INTERNAL | ||||
|    // COMPILER ERROR in MSVC without STLport. I'm clueless as to why. | ||||
| #if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT) | ||||
|     // Test user-defined type. | ||||
|     test_integer<my_int1>(); | ||||
|     test_integer<my_int2>(); | ||||
|     test_integer<my_int3>(); | ||||
|      | ||||
|    // Some tests on container iterators, to prove we handle a few different categories | ||||
|     test_container<std::vector<int> >(); | ||||
|     test_container<std::list<int> >(); | ||||
| # ifndef BOOST_NO_SLIST | ||||
|     test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >(); | ||||
| # endif | ||||
|      | ||||
|     // Also prove that we can handle raw pointers. | ||||
|     int array[2000]; | ||||
|     test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1)); | ||||
| #endif | ||||
|     std::cout << "test successful " << std::endl; | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										273
									
								
								filter_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								filter_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>Filter Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" | ||||
| align="center" width="277" height="86"> | ||||
|  | ||||
| <h1>Filter Iterator Adaptor</h1> | ||||
|  | ||||
| Defined in header | ||||
| <a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a> | ||||
|  | ||||
|  | ||||
| <p> | ||||
| The filter iterator adaptor creates a view of an iterator range in | ||||
| which some elements of the range are skipped over. A <a | ||||
| href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> | ||||
| function object controls which elements are skipped. When the | ||||
| predicate is applied to an element, if it returns <tt>true</tt> then | ||||
| the element is retained and if it returns <tt>false</tt> then the | ||||
| element is skipped over. | ||||
|  | ||||
|  | ||||
| <h2>Synopsis</h2> | ||||
|  | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class Predicate, class BaseIterator, ...> | ||||
|   class filter_iterator_generator; | ||||
|  | ||||
|   template <class Predicate, class BaseIterator> | ||||
|   typename filter_iterator_generator<Predicate, BaseIterator>::type | ||||
|   make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate()); | ||||
| } | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <h2><a name="filter_iterator_generator">The Filter Iterator Type | ||||
| Generator</a></h2> | ||||
|  | ||||
| The class <tt>filter_iterator_generator</tt> is a helper class whose | ||||
| purpose is to construct a filter iterator type.  The template | ||||
| parameters for this class are the <tt>Predicate</tt> function object | ||||
| type and the <tt>BaseIterator</tt> type that is being wrapped.  In | ||||
| most cases the associated types for the wrapped iterator can be | ||||
| deduced from <tt>std::iterator_traits</tt>, but in some situations the | ||||
| user may want to override these types, so there are also template | ||||
| parameters for each of the iterator's associated types. | ||||
|  | ||||
| <pre> | ||||
| template <class Predicate, class BaseIterator, | ||||
|           class Value, class Reference, class Pointer, class Category, class Distance> | ||||
| class filter_iterator_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting filter iterator type  | ||||
| } | ||||
| </pre> | ||||
|  | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| The following example uses filter iterator to print out all the | ||||
| positive integers in an array.  | ||||
|  | ||||
| <pre> | ||||
| struct is_positive_number { | ||||
|   bool operator()(int x) { return 0 < x; } | ||||
| }; | ||||
| int main() { | ||||
|   int numbers[] = { 0, -1, 4, -3, 5, 8, -2 }; | ||||
|   const int N = sizeof(numbers)/sizeof(int); | ||||
|  | ||||
|   typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type FilterIter; | ||||
|   is_positive_number predicate; | ||||
|   FilterIter::policies_type policies(predicate, numbers + N); | ||||
|   FilterIter filter_iter_first(numbers, policies); | ||||
|   FilterIter filter_iter_last(numbers + N, policies); | ||||
|  | ||||
|   std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| 4 5 8 | ||||
| </pre> | ||||
|  | ||||
|  | ||||
| <h3>Template Parameters</h3> | ||||
|  | ||||
| <Table border> | ||||
| <TR> | ||||
| <TH>Parameter</TH><TH>Description</TH> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><a href="http://www.sgi.com/tech/stl/Predicate.html"><tt>Predicate</tt></a></TD> | ||||
| <TD>The function object that determines which elements are retained and which elements are skipped. | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>BaseIterator</tt></TD> | ||||
| <TD>The iterator type being wrapped. This type must at least be a model | ||||
|  of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Value</tt></TD> | ||||
| <TD>The <tt>value_type</tt> of the resulting iterator, | ||||
| unless const. If const, a conforming compiler strips constness for the | ||||
| <tt>value_type</tt>. Typically the default for this parameter is the | ||||
| appropriate type<a href="#1">[1]</a>.<br> <b>Default:</b> | ||||
| <tt>std::iterator_traits<BaseIterator>::value_type</TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Reference</tt></TD> | ||||
| <TD>The <tt>reference</tt> type of the resulting iterator, and in | ||||
| particular, the result type of <tt>operator*()</tt>. Typically the default for | ||||
| this parameter is the appropriate type.<br> <b>Default:</b> If | ||||
| <tt>Value</tt> is supplied, <tt>Value&</tt> is used. Otherwise | ||||
| <tt>std::iterator_traits<BaseIterator>::reference</tt> is | ||||
| used.</TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Pointer</tt></TD> | ||||
| <TD>The <tt>pointer</tt> type of the resulting iterator, and in | ||||
|  particular, the result type of <tt>operator->()</tt>.  | ||||
|  Typically the default for | ||||
| this parameter is the appropriate type.<br> | ||||
| <b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>, | ||||
| otherwise <tt>std::iterator_traits<BaseIterator>::pointer</tt>.</TD> | ||||
| </TR> | ||||
|  | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Category</tt></TD> | ||||
| <TD>The <tt>iterator_category</tt> type for the resulting iterator. | ||||
| Typically the | ||||
| default for this parameter is the appropriate type. If you override | ||||
| this parameter, do not use <tt>bidirectional_iterator_tag</tt> | ||||
| because filter iterators can not go in reverse.<br> | ||||
| <b>Default:</b> <tt>std::iterator_traits<BaseIterator>::iterator_category</tt></TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>Distance</tt></TD> | ||||
| <TD>The <tt>difference_type</tt> for the resulting iterator. Typically the default for | ||||
| this parameter is the appropriate type.<br> | ||||
| <b>Default:</b> <tt>std::iterator_traits<BaseIterator>::difference_type</TD> | ||||
| </TR> | ||||
|  | ||||
| </table> | ||||
|  | ||||
|  | ||||
| <h3>Model of</h3> | ||||
|  | ||||
| The filter iterator adaptor (the type | ||||
| <tt>filter_iterator_generator<...>::type</tt>) may be a model of <a | ||||
| href="http://www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> or <a | ||||
| href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a> | ||||
| depending on the adapted iterator type. | ||||
|  | ||||
|  | ||||
| <h3>Members</h3> | ||||
|  | ||||
| The filter iterator type implements all of the member functions and | ||||
| operators required of the <a | ||||
| href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a> | ||||
| concept.  In addition it has the following constructor: | ||||
|  | ||||
| <pre>filter_iterator_generator::type(const BaseIterator& it, const Policies& p = Policies())</pre> | ||||
|  | ||||
| <p> | ||||
| The policies type has only one public function, which is its constructor: | ||||
|  | ||||
| <pre>filter_iterator_generator::policies_type(const Predicate& p, const BaseIterator& end)</pre> | ||||
|  | ||||
| <p> | ||||
| <hr> | ||||
| <p> | ||||
|  | ||||
| <h2><a name="make_filter_iterator">The Make Filter Iterator Function</a></h2> | ||||
|  | ||||
| <pre> | ||||
| template <class Predicate, class BaseIterator> | ||||
| typename detail::filter_generator<Predicate, BaseIterator>::type | ||||
| make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate()) | ||||
| </pre> | ||||
|  | ||||
| This function provides a convenient way to create filter iterators. | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In this example we print out all numbers in the array that are | ||||
| greater than negative two. | ||||
|  | ||||
| <pre> | ||||
| int main() | ||||
| { | ||||
|   int numbers[] = { 0, -1, 4, -3, 5, 8, -2 }; | ||||
|   const int N = sizeof(numbers)/sizeof(int); | ||||
|  | ||||
|   std::copy(boost::make_filter_iterator(numbers, numbers + N,  | ||||
| 					std::bind2nd(std::greater<int>(), -2)), | ||||
| 	    boost::make_filter_iterator(numbers + N, numbers + N,  | ||||
| 					std::bind2nd(std::greater<int>(), -2)), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
| } | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| 0 -1 4 5 8  | ||||
| </pre> | ||||
|  | ||||
| <p> | ||||
| In the next example we print the positive numbers using the | ||||
| <tt>make_filter_iterator()</tt> function. | ||||
|  | ||||
| <pre> | ||||
| struct is_positive_number { | ||||
|   bool operator()(int x) { return 0 < x; } | ||||
| }; | ||||
| int main() | ||||
| { | ||||
|   int numbers[] = { 0, -1, 4, -3, 5, 8, -2 }; | ||||
|   const int N = sizeof(numbers)/sizeof(int); | ||||
|  | ||||
|   std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N), | ||||
| 	    boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| 4 5 8 | ||||
| </pre> | ||||
|  | ||||
|  | ||||
| <h3>Notes</h3> | ||||
|  | ||||
| <a name="1">[1]</a> If the compiler does not support partial | ||||
| specialization and the wrapped iterator type is a builtin pointer then | ||||
| the <tt>Value</tt> type must be explicitly specified (don't use the | ||||
| default). | ||||
|  | ||||
|  | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->09 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14894" --></p> | ||||
| <p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use, | ||||
| modify, sell and distribute this document is granted provided this copyright | ||||
| notice appears in all copies. This document is provided "as is" | ||||
| without express or implied warranty, and with no claim as to its suitability for | ||||
| any purpose.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										53
									
								
								filter_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								filter_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // Example of using the filter iterator adaptor from | ||||
| // boost/iterator_adaptors.hpp. | ||||
|  | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <algorithm> | ||||
| #include <functional> | ||||
| #include <iostream> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| struct is_positive_number { | ||||
|   bool operator()(int x) { return 0 < x; } | ||||
| }; | ||||
|  | ||||
| int main() | ||||
| { | ||||
|   int numbers[] = { 0, -1, 4, -3, 5, 8, -2 }; | ||||
|   const int N = sizeof(numbers)/sizeof(int); | ||||
|  | ||||
|   // Example using make_filter_iterator() | ||||
|   std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N), | ||||
| 	    boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // Example using filter_iterator_generator | ||||
|   typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type | ||||
|     FilterIter; | ||||
|   is_positive_number predicate; | ||||
|   FilterIter::policies_type policies(predicate, numbers + N); | ||||
|   FilterIter filter_iter_first(numbers, policies); | ||||
|   FilterIter filter_iter_last(numbers + N, policies); | ||||
|  | ||||
|   std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // Another example using make_filter_iterator() | ||||
|   std::copy(boost::make_filter_iterator(numbers, numbers + N,  | ||||
| 					std::bind2nd(std::greater<int>(), -2)), | ||||
| 	    boost::make_filter_iterator(numbers + N, numbers + N,  | ||||
| 					std::bind2nd(std::greater<int>(), -2)), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										41
									
								
								fun_out_iter_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								fun_out_iter_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| // (C) Copyright Jeremy Siek 2001. Permission to copy, use, modify, | ||||
| // sell and distribute this software is granted provided this | ||||
| // copyright notice appears in all copies. This software is provided | ||||
| // "as is" without express or implied warranty, and with no claim as | ||||
| // to its suitability for any purpose. | ||||
|  | ||||
| // Revision History: | ||||
|  | ||||
| // 27 Feb 2001   Jeremy Siek | ||||
| //      Initial checkin. | ||||
|  | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #include <boost/function_output_iterator.hpp> | ||||
|  | ||||
| struct string_appender { | ||||
|   string_appender(std::string& s) : m_str(s) { } | ||||
|   void operator()(const std::string& x) const { | ||||
|     m_str += x; | ||||
|   } | ||||
|   std::string& m_str; | ||||
| }; | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   std::vector<std::string> x; | ||||
|   x.push_back("hello"); | ||||
|   x.push_back(" "); | ||||
|   x.push_back("world"); | ||||
|   x.push_back("!"); | ||||
|  | ||||
|   std::string s = ""; | ||||
|   std::copy(x.begin(), x.end(),  | ||||
| 	    boost::make_function_output_iterator(string_appender(s))); | ||||
|    | ||||
|   std::cout << s << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										169
									
								
								function_output_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								function_output_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> | ||||
|  | ||||
| <html> | ||||
| <head> | ||||
|     <meta name="generator" content="HTML Tidy, see www.w3.org"> | ||||
|     <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
|     <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
|     <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
|  | ||||
|     <title>Function Output Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|          | ||||
|     <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align= | ||||
|     "center" width="277" height="86">  | ||||
|  | ||||
|     <h1>Function Output Iterator Adaptor</h1> | ||||
|     Defined in header <a href= | ||||
|     "../../boost/function_output_iterator.hpp">boost/function_output_iterator.hpp</a>  | ||||
|  | ||||
|     <p>The function output iterator adaptor makes it easier to create | ||||
|     custom output iterators. The adaptor takes a <a | ||||
|     href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary | ||||
|     Function</a> and creates a model of <a | ||||
|     href="http://www.sgi.com/tech/stl/OutputIterator.html">Output | ||||
|     Iterator</a>. Each item assigned to the output iterator is passed | ||||
|     as an argument to the unary function.  The motivation for this | ||||
|     iterator is that creating a C++ Standard conforming output | ||||
|     iterator is non-trivial, particularly because the proper | ||||
|     implementation usually requires a proxy object. On the other hand, | ||||
|     creating a function (or function object) is much simpler. | ||||
|  | ||||
|     <h2>Synopsis</h2> | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class UnaryFunction> | ||||
|   class function_output_iterator; | ||||
|  | ||||
|   template <class UnaryFunction> | ||||
|   function_output_iterator<UnaryFunction> | ||||
|   make_function_output_iterator(const UnaryFunction& f = UnaryFunction()) | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|      | ||||
|     In this example we create an output iterator that appends | ||||
|     each item onto the end of a string, using the <tt>string_appender</tt> | ||||
|     function.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #include <boost/function_output_iterator.hpp> | ||||
|  | ||||
| struct string_appender { | ||||
|   string_appender(std::string& s) : m_str(s) { } | ||||
|   void operator()(const std::string& x) const { | ||||
|     m_str += x; | ||||
|   } | ||||
|   std::string& m_str; | ||||
| }; | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   std::vector<std::string> x; | ||||
|   x.push_back("hello"); | ||||
|   x.push_back(" "); | ||||
|   x.push_back("world"); | ||||
|   x.push_back("!"); | ||||
|  | ||||
|   std::string s = ""; | ||||
|   std::copy(x.begin(), x.end(),  | ||||
|             boost::make_function_output_iterator(string_appender(s))); | ||||
|    | ||||
|   std::cout << s << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <hr> | ||||
|  | ||||
|     <h2><a name="function_output_iterator">The Function Output Iterator Class</a></h2> | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class UnaryFunction> | ||||
| class function_output_iterator; | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     The <tt>function_output_iterator</tt> class creates an <a | ||||
|     href="http://www.sgi.com/tech/stl/OutputIterator.html">Output | ||||
|     Iterator</a> out of a | ||||
|     <a href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary | ||||
|     Function</a>. Each item assigned to the output iterator is passed | ||||
|     as an argument to the unary function. | ||||
|  | ||||
|     <h3>Template Parameters</h3> | ||||
|  | ||||
|     <table border> | ||||
|       <tr> | ||||
|         <th>Parameter | ||||
|  | ||||
|         <th>Description | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>UnaryFunction</tt>  | ||||
|  | ||||
|         <td>The function type being wrapped. The return type of the | ||||
|         function is not used, so it can be <tt>void</tt>.  The | ||||
|         function must be a model of <a | ||||
|         href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary | ||||
|         Function</a>.</td> | ||||
|     </table> | ||||
|  | ||||
|     <h3>Concept Model</h3> | ||||
|     The function output iterator class is a model of <a | ||||
|     href="http://www.sgi.com/tech/stl/OutputIterator.html">Output | ||||
|     Iterator</a>. | ||||
|  | ||||
|     <h2>Members</h3> | ||||
|     The function output iterator implements the member functions | ||||
|     and operators required of the <a | ||||
|     href="http://www.sgi.com/tech/stl/OutputIterator.html">Output | ||||
|     Iterator</a> concept. In addition it has the following constructor: | ||||
| <pre> | ||||
| explicit function_output_iterator(const UnaryFunction& f = UnaryFunction()) | ||||
| </pre> | ||||
|    <br>     | ||||
|     <br> | ||||
|  | ||||
|     <hr> | ||||
|     <h2><a name="make_function_output_iterator">The Function Output Iterator Object | ||||
|     Generator</a></h2> | ||||
|  | ||||
|     The <tt>make_function_output_iterator()</tt> function provides a | ||||
|     more convenient way to create function output iterator objects. The | ||||
|     function saves the user the trouble of explicitly writing out the | ||||
|     iterator types. If the default argument is used, the function | ||||
|     type must be provided as an explicit template argument. | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class UnaryFunction> | ||||
| function_output_iterator<UnaryFunction> | ||||
| make_function_output_iterator(const UnaryFunction& f = UnaryFunction()) | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <hr> | ||||
|  | ||||
|     <p>© Copyright Jeremy Siek 2001. Permission to copy, use, | ||||
|     modify, sell and distribute this document is granted provided this | ||||
|     copyright notice appears in all copies. This document is provided | ||||
|     "as is" without express or implied warranty, and with no claim as | ||||
|     to its suitability for any purpose. | ||||
|  | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										366
									
								
								half_open_range_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								half_open_range_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,366 @@ | ||||
| // (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears in | ||||
| // all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
| // | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
| // | ||||
| // Revision History | ||||
| // 11 Feb 2001  Compile with Borland, re-enable failing tests (David Abrahams) | ||||
| // 29 Jan 2001  Initial revision (David Abrahams) | ||||
|  | ||||
| #include <boost/half_open_range.hpp> | ||||
| #include <boost/utility.hpp> | ||||
| #include <iterator> | ||||
| #include <stdlib.h> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| #include <cassert> | ||||
| #include <stdexcept> | ||||
| #ifndef BOOST_NO_LIMITS | ||||
| # include <limits> | ||||
| #endif | ||||
| #ifndef BOOST_NO_SLIST | ||||
| # include <slist> | ||||
| #endif | ||||
|  | ||||
| inline unsigned unsigned_random(unsigned max) | ||||
| { | ||||
|     return (max > 0) ? (unsigned)rand() % max : 0; | ||||
| } | ||||
|  | ||||
| // Special tests for ranges supporting random access | ||||
| template <class T> | ||||
| void category_test_1( | ||||
|     const boost::half_open_range<T>& r, std::random_access_iterator_tag) | ||||
| { | ||||
|     typedef boost::half_open_range<T> range; | ||||
|     typedef typename range::size_type size_type; | ||||
|     size_type size = r.size(); | ||||
|  | ||||
|     // pick a random offset | ||||
|     size_type offset = unsigned_random(size); | ||||
|  | ||||
|     typename range::value_type x = *(r.begin() + offset); | ||||
|     // test contains(value_type) | ||||
|     assert(r.contains(r.start()) == !r.empty()); | ||||
|     assert(!r.contains(r.finish())); | ||||
|     assert(r.contains(x) == (offset != size)); | ||||
|  | ||||
|     range::const_iterator p = r.find(x); | ||||
|     assert((p == r.end()) == (x == r.finish())); | ||||
|     assert(r.find(r.finish()) == r.end()); | ||||
|  | ||||
|     if (offset != size) | ||||
|     { | ||||
|         assert(x == r[offset]); | ||||
|         assert(x == r.at(offset)); | ||||
|     } | ||||
|  | ||||
|     bool caught_out_of_range = false; | ||||
|     try { | ||||
|         bool never_initialized = x == r.at(size); | ||||
|         (void)never_initialized; | ||||
|     } | ||||
|     catch(std::out_of_range&) | ||||
|     { | ||||
|         caught_out_of_range = true; | ||||
|     } | ||||
|     catch(...) | ||||
|     { | ||||
|     } | ||||
|     assert(caught_out_of_range); | ||||
| } | ||||
|  | ||||
| // Those tests must be skipped for other ranges | ||||
| template <class T> | ||||
| void category_test_1( | ||||
|     const boost::half_open_range<T>&, std::forward_iterator_tag) | ||||
| { | ||||
| } | ||||
|  | ||||
| unsigned indices[][2] = { {0,0},{0,1},{0,2},{0,3}, | ||||
|                                 {1,1},{1,2},{1,3}, | ||||
|                                       {2,2},{2,3}, | ||||
|                                             {3,3}}; | ||||
|  | ||||
| template <class Range> | ||||
| void category_test_2( | ||||
|     const std::vector<Range>& ranges, unsigned i, unsigned j, std::random_access_iterator_tag) | ||||
| { | ||||
|     typedef Range range; | ||||
|     const range& ri = ranges[i]; | ||||
|     const range& rj = ranges[j]; | ||||
|  | ||||
|     if (indices[i][0] <= indices[j][0] && indices[i][1] >= indices[j][1]) | ||||
|         assert(ri.contains(rj)); | ||||
|  | ||||
|     if (ri.contains(rj)) | ||||
|         assert((ri & rj) == rj); | ||||
|     assert(boost::intersects(ri, rj) == !(ri & rj).empty()); | ||||
|  | ||||
|     range t1(ri); | ||||
|     t1 &= rj; | ||||
|     assert(t1 == range(indices[i][0] > indices[j][0] ? ri.start() : rj.start(), | ||||
|                        indices[i][1] < indices[j][1] ? ri.finish() : rj.finish())); | ||||
|     assert(t1 == (ri & rj)); | ||||
|      | ||||
|     range t2(ri); | ||||
|     t2 |= rj; | ||||
|      | ||||
|     if (ri.empty()) | ||||
|         assert(t2 == rj); | ||||
|     else if (rj.empty()) | ||||
|         assert(t2 == ri); | ||||
|     else | ||||
|         assert(t2 == range(indices[i][0] < indices[j][0] ? ri.start() : rj.start(), | ||||
|                            indices[i][1] > indices[j][1] ? ri.finish() : rj.finish())); | ||||
|     assert(t2 == (ri | rj)); | ||||
|     if (i == j) | ||||
|         assert(ri == rj); | ||||
|      | ||||
|     if (ri.empty() || rj.empty()) | ||||
|         assert((ri == rj) == (ri.empty() && rj.empty())); | ||||
|     else | ||||
|         assert((ri == rj) == (ri.start() == rj.start() && ri.finish() == rj.finish())); | ||||
|  | ||||
|     assert((ri == rj) == !(ri != rj)); | ||||
|  | ||||
|     bool same = ri == rj; | ||||
|     bool one_empty = ri.empty() != rj.empty(); | ||||
|  | ||||
|     std::less<range> less; | ||||
|     std::less_equal<range> less_equal; | ||||
|     std::greater<range> greater; | ||||
|     std::greater_equal<range> greater_equal; | ||||
|      | ||||
|     if (same) | ||||
|     { | ||||
|         assert(greater_equal(ri,rj)); | ||||
|         assert(less_equal(ri,rj)); | ||||
|         assert(!greater(ri,rj)); | ||||
|         assert(!less(ri,rj)); | ||||
|     } | ||||
|     else if (one_empty) | ||||
|     { | ||||
|         const range& empty = ri.empty() ? ri : rj; | ||||
|         const range& non_empty = rj.empty() ? ri : rj; | ||||
|          | ||||
|         assert(less(empty,non_empty)); | ||||
|         assert(less_equal(empty,non_empty)); | ||||
|         assert(!greater(empty,non_empty)); | ||||
|         assert(!greater_equal(empty,non_empty)); | ||||
|         assert(!less(non_empty,empty)); | ||||
|         assert(!less_equal(non_empty,empty)); | ||||
|         assert(greater(non_empty,empty)); | ||||
|         assert(greater_equal(non_empty,empty)); | ||||
|     } | ||||
|     else { | ||||
|         if (indices[i][0] < indices[j][0] || | ||||
|             indices[i][0] == indices[j][0] && indices[i][1] < indices[j][1]) | ||||
|         { | ||||
|             assert(!greater_equal(ri,rj)); | ||||
|             assert(less(ri,rj)); | ||||
|         } | ||||
|  | ||||
|         if (indices[i][0] < indices[j][0] || | ||||
|             indices[i][0] == indices[j][0] && indices[i][1] <= indices[j][1]) | ||||
|         { | ||||
|             assert(!greater(ri,rj)); | ||||
|             assert(less_equal(ri,rj)); | ||||
|         } | ||||
|  | ||||
|         if (indices[i][0] > indices[j][0] || | ||||
|             indices[i][0] == indices[j][0] && indices[i][1] > indices[j][1]) | ||||
|         { | ||||
|             assert(!less_equal(ri,rj)); | ||||
|             assert(greater(ri,rj)); | ||||
|         } | ||||
|  | ||||
|         if (indices[i][0] > indices[j][0] || | ||||
|             indices[i][0] == indices[j][0] && indices[i][1] >= indices[j][1]) | ||||
|         { | ||||
|             assert(!less(ri,rj)); | ||||
|             assert(greater_equal(ri,rj)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| template <class Range> | ||||
| void category_test_2( | ||||
|     const std::vector<Range>&, unsigned, unsigned, std::forward_iterator_tag) | ||||
| { | ||||
| } | ||||
|  | ||||
| template <class T> | ||||
| void category_test_2( | ||||
|     const std::vector<boost::half_open_range<T> >&, unsigned, unsigned, std::bidirectional_iterator_tag) | ||||
| { | ||||
| } | ||||
|  | ||||
| template <class Range> | ||||
| void test_back(Range& x, std::bidirectional_iterator_tag) | ||||
| { | ||||
|     assert(x.back() == boost::prior(x.finish())); | ||||
| } | ||||
|  | ||||
| template <class Range> | ||||
| void test_back(Range& x, std::forward_iterator_tag) | ||||
| { | ||||
| } | ||||
|  | ||||
| template <class T> | ||||
| boost::half_open_range<T> range_identity(const boost::half_open_range<T>& x) | ||||
| { | ||||
|     return x; | ||||
| } | ||||
|  | ||||
| template <class T> | ||||
| void test(T x0, T x1, T x2, T x3) | ||||
| { | ||||
|     std::vector<boost::half_open_range<T> > ranges; | ||||
|     typedef boost::half_open_range<T> range; | ||||
|  | ||||
|     T bounds[4] = { x0, x1, x2, x3 }; | ||||
|  | ||||
|     const std::size_t num_ranges = sizeof(indices)/sizeof(*indices); | ||||
|     // test construction | ||||
|     for (std::size_t n = 0; n < num_ranges;++n) | ||||
|     { | ||||
|         T start = bounds[indices[n][0]]; | ||||
|         T finish = bounds[indices[n][1]]; | ||||
|         boost::half_open_range<T> r(start, finish); | ||||
|         ranges.push_back(r); | ||||
|     } | ||||
|      | ||||
|     // test implicit conversion from std::pair<T,T> | ||||
|     range converted = std::pair<T,T>(x0,x0); | ||||
|     (void)converted; | ||||
|  | ||||
|     // test assignment, equality and inequality | ||||
|     range r00 = range(x0, x0); | ||||
|     assert(r00 == range(x0,x0)); | ||||
|     assert(r00 == range(x1,x1)); // empty ranges are all equal | ||||
|     if (x3 != x0) | ||||
|         assert(r00 != range(x0, x3)); | ||||
|     r00 = range(x0, x3); | ||||
|     assert(r00 == range(x0, x3)); | ||||
|     if (x3 != x0) | ||||
|         assert(r00 != range(x0, x0)); | ||||
|  | ||||
|     typedef typename range::iterator iterator; | ||||
|     typedef typename iterator::iterator_category category; | ||||
|      | ||||
|     for (unsigned i = 0; i < num_ranges; ++i) | ||||
|     { | ||||
|         const range& r = ranges[i]; | ||||
|              | ||||
|         // test begin(), end(), basic iteration. | ||||
|         unsigned count = 0; | ||||
|         for (range::const_iterator p = r.begin(), finish = r.end(); | ||||
|              p != finish; | ||||
|              ++p, ++count) | ||||
|         { | ||||
|             assert(count < 2100); | ||||
|         } | ||||
|  | ||||
|         // test size(), empty(), front(), back() | ||||
|         assert((unsigned)r.size() == count); | ||||
|         if (indices[i][0] == indices[i][1]) | ||||
|             assert(r.empty()); | ||||
|         if (r.empty()) | ||||
|             assert(r.size() == 0); | ||||
|         if (!r.empty()) | ||||
|         { | ||||
|             assert(r.front() == r.start()); | ||||
|             test_back(r, category()); | ||||
|         } | ||||
|  | ||||
|             // test swap | ||||
|         range r1(r); | ||||
|         range r2(x0,x3); | ||||
|         const bool same = r1 == r2; | ||||
|         r1.swap(r2); | ||||
|         assert(r1 == range(x0,x3)); | ||||
|         assert(r2 == r); | ||||
|         if (!same) { | ||||
|             assert(r1 != r); | ||||
|             assert(r2 != range(x0,x3)); | ||||
|         } | ||||
|  | ||||
|         // do individual tests for random-access iterators | ||||
|         category_test_1(r, category()); | ||||
|     } | ||||
|  | ||||
|     for (unsigned j = 0; j < num_ranges; ++j) { | ||||
|         for (unsigned k = 0; k < num_ranges; ++k) { | ||||
|             category_test_2(ranges, j, k, category()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| template <class Integer> | ||||
| void test_integer(Integer* = 0) // default arg works around MSVC bug | ||||
| { | ||||
|     Integer a = 0; | ||||
|     Integer b = a + unsigned_random(128 - a); | ||||
|     Integer c = b + unsigned_random(128 - b); | ||||
|     Integer d = c + unsigned_random(128 - c); | ||||
|  | ||||
|     test(a, b, c, d); | ||||
| } | ||||
|  | ||||
| template <class Container> | ||||
| void test_container(Container* = 0)  // default arg works around MSVC bug | ||||
| { | ||||
|     Container c(unsigned_random(1673)); | ||||
|  | ||||
|     const typename Container::size_type offset1 = unsigned_random(c.size()); | ||||
|     const typename Container::size_type offset2 = unsigned_random(c.size() - offset1); | ||||
|     typename Container::iterator internal1 = c.begin(); | ||||
|     std::advance(internal1, offset1); | ||||
|     typename Container::iterator internal2 = internal1; | ||||
|     std::advance(internal2, offset2); | ||||
|      | ||||
|     test(c.begin(), internal1, internal2, c.end()); | ||||
|  | ||||
|     typedef typename Container::const_iterator const_iterator; | ||||
|     test(const_iterator(c.begin()), | ||||
|          const_iterator(internal1), | ||||
|          const_iterator(internal2), | ||||
|          const_iterator(c.end())); | ||||
| } | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     // Test the built-in integer types. | ||||
|     test_integer<char>(); | ||||
|     test_integer<unsigned char>(); | ||||
|     test_integer<signed char>(); | ||||
|     test_integer<wchar_t>(); | ||||
|     test_integer<short>(); | ||||
|     test_integer<unsigned short>(); | ||||
|     test_integer<int>(); | ||||
|     test_integer<unsigned int>(); | ||||
|     test_integer<long>(); | ||||
|     test_integer<unsigned long>(); | ||||
| #if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX) | ||||
|     test_integer<long long>(); | ||||
|     test_integer<unsigned long long>(); | ||||
| #endif | ||||
|     // Some tests on container iterators, to prove we handle a few different categories | ||||
|     test_container<std::vector<int> >(); | ||||
|     test_container<std::list<int> >(); | ||||
| #ifndef BOOST_NO_SLIST | ||||
|     test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >(); | ||||
| #endif | ||||
|     // Also prove that we can handle raw pointers. | ||||
|     int array[2000]; | ||||
|     const std::size_t a = 0; | ||||
|     const std::size_t b = a + unsigned_random(2000 - a); | ||||
|     const std::size_t c = b + unsigned_random(2000 - b); | ||||
|     test(array, array+b, array+c, array+2000); | ||||
|     return 0; | ||||
| } | ||||
| @@ -23,8 +23,11 @@ | ||||
| #include <boost/config.hpp> | ||||
| #endif | ||||
|  | ||||
| #ifndef BOOST_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits.hpp> | ||||
| #ifndef BOOST_ARITHMETIC_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/arithmetic_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_COMPOSITE_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/composite_traits.hpp> | ||||
| #endif | ||||
|  | ||||
| namespace boost{ | ||||
|   | ||||
| @@ -19,8 +19,11 @@ | ||||
| #define BOOST_DETAIL_COMPRESSED_PAIR_HPP | ||||
|  | ||||
| #include <algorithm> | ||||
| #ifndef BOOST_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits.hpp> | ||||
| #ifndef BOOST_OBJECT_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/object_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_SAME_TRAITS_HPP | ||||
| #include <boost/type_traits/same_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_CALL_TRAITS_HPP | ||||
| #include <boost/call_traits.hpp> | ||||
| @@ -422,3 +425,4 @@ swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y) | ||||
| #endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -24,8 +24,11 @@ | ||||
| #include <boost/config.hpp> | ||||
| #endif | ||||
|  | ||||
| #ifndef BOOST_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits.hpp> | ||||
| #ifndef BOOST_ARITHMETIC_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/arithmetic_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_COMPOSITE_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/composite_traits.hpp> | ||||
| #endif | ||||
|  | ||||
| namespace boost{ | ||||
|   | ||||
| @@ -8,6 +8,8 @@ | ||||
| //  see libs/utility/compressed_pair.hpp | ||||
| // | ||||
| /* Release notes: | ||||
|    20 Jan 2001: | ||||
|         Fixed obvious bugs (David Abrahams) | ||||
| 	07 Oct 2000: | ||||
| 		Added better single argument constructor support. | ||||
|    03 Oct 2000: | ||||
| @@ -24,8 +26,11 @@ | ||||
| #define BOOST_OB_COMPRESSED_PAIR_HPP | ||||
|  | ||||
| #include <algorithm> | ||||
| #ifndef BOOST_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits.hpp> | ||||
| #ifndef BOOST_OBJECT_TYPE_TRAITS_HPP | ||||
| #include <boost/type_traits/object_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_SAME_TRAITS_HPP | ||||
| #include <boost/type_traits/same_traits.hpp> | ||||
| #endif | ||||
| #ifndef BOOST_CALL_TRAITS_HPP | ||||
| #include <boost/call_traits.hpp> | ||||
| @@ -42,10 +47,14 @@ namespace boost | ||||
| // have one template single-argument constructor | ||||
| // in place of two specific constructors: | ||||
| // | ||||
|  | ||||
| template <class T1, class T2> | ||||
| class compressed_pair; | ||||
|  | ||||
| namespace detail{ | ||||
|  | ||||
| template <class A, class T1, class T2> | ||||
| struct best_convertion_traits | ||||
| struct best_conversion_traits | ||||
| { | ||||
|    typedef char one; | ||||
|    typedef char (&two)[2]; | ||||
| @@ -102,10 +111,20 @@ public: | ||||
|    template <class A> | ||||
|    explicit compressed_pair_0(const A& val) | ||||
|    { | ||||
|       init_one<best_convertion_traits<A, T1, T2>::value>::init(val, &_first, &_second); | ||||
|       init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, &_second); | ||||
|    } | ||||
|    compressed_pair_0(const compressed_pair_0<T1,T2>& x) | ||||
|       : _first(x._first), _second(x._second) {} | ||||
|    compressed_pair_0(const ::boost::compressed_pair<T1,T2>& x) | ||||
|       : _first(x.first()), _second(x.second()) {} | ||||
|  | ||||
| #if 0 | ||||
|   compressed_pair_0& operator=(const compressed_pair_0& x) { | ||||
|     cout << "assigning compressed pair 0" << endl; | ||||
|     _first = x._first; | ||||
|     _second = x._second; | ||||
|     cout << "finished assigning compressed pair 0" << endl; | ||||
|     return *this; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|    first_reference       first()       { return _first; } | ||||
|    first_const_reference first() const { return _first; } | ||||
| @@ -139,13 +158,26 @@ public: | ||||
|  | ||||
|             compressed_pair_1() : T2(), _first() {} | ||||
|             compressed_pair_1(first_param_type x, second_param_type y) : T2(y), _first(x) {} | ||||
|  | ||||
|    template <class A> | ||||
|    explicit compressed_pair_1(const A& val) | ||||
|    { | ||||
|       init_one<best_convertion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this)); | ||||
|       init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this)); | ||||
|    } | ||||
|    compressed_pair_1(const compressed_pair_1<T1,T2>& x) | ||||
|       : T2(x), _first(x._first) {} | ||||
|  | ||||
|    compressed_pair_1(const ::boost::compressed_pair<T1,T2>& x) | ||||
|       : T2(x.second()), _first(x.first()) {} | ||||
|  | ||||
| #ifdef BOOST_MSVC | ||||
|   // Total weirdness. If the assignment to _first is moved after | ||||
|   // the call to the inherited operator=, then this breaks graph/test/graph.cpp | ||||
|   // by way of iterator_adaptor. | ||||
|   compressed_pair_1& operator=(const compressed_pair_1& x) { | ||||
|     _first = x._first; | ||||
|     T2::operator=(x); | ||||
|     return *this; | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|    first_reference       first()       { return _first; } | ||||
|    first_const_reference first() const { return _first; } | ||||
| @@ -182,11 +214,20 @@ public: | ||||
|    template <class A> | ||||
|    explicit compressed_pair_2(const A& val) | ||||
|    { | ||||
|       init_one<best_convertion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second); | ||||
|       init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second); | ||||
|    } | ||||
|    compressed_pair_2(const compressed_pair_2<T1,T2>& x) | ||||
|       : T1(x), _second(x._second) {} | ||||
|    compressed_pair_2(const ::boost::compressed_pair<T1,T2>& x) | ||||
|       : T1(x.first()), _second(x.second()) {} | ||||
|  | ||||
| #if 0 | ||||
|   compressed_pair_2& operator=(const compressed_pair_2& x) { | ||||
|     cout << "assigning compressed pair 2" << endl; | ||||
|     T1::operator=(x); | ||||
|     _second = x._second; | ||||
|     cout << "finished assigning compressed pair 2" << endl; | ||||
|     return *this; | ||||
|   } | ||||
| #endif | ||||
|    first_reference       first()       { return *this; } | ||||
|    first_const_reference first() const { return *this; } | ||||
|  | ||||
| @@ -220,10 +261,10 @@ public: | ||||
|    template <class A> | ||||
|    explicit compressed_pair_3(const A& val) | ||||
|    { | ||||
|       init_one<best_convertion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this)); | ||||
|       init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this)); | ||||
|    } | ||||
|    compressed_pair_3(const compressed_pair_3<T1,T2>& x) | ||||
|       : T1(x), T2(x) {} | ||||
|    compressed_pair_3(const ::boost::compressed_pair<T1,T2>& x) | ||||
|       : T1(x.first()), T2(x.second()) {} | ||||
|  | ||||
|    first_reference       first()       { return *this; } | ||||
|    first_const_reference first() const { return *this; } | ||||
| @@ -255,8 +296,8 @@ public: | ||||
|             compressed_pair_4(first_param_type x, second_param_type) : T1(x) {} | ||||
|    // only one single argument constructor since T1 == T2 | ||||
|    explicit compressed_pair_4(first_param_type x) : T1(x) {} | ||||
|    compressed_pair_4(const compressed_pair_4& x) | ||||
|       : T1(x){} | ||||
|    compressed_pair_4(const ::boost::compressed_pair<T1,T2>& x) | ||||
|       : T1(x.first()){} | ||||
|  | ||||
|    first_reference       first()       { return *this; } | ||||
|    first_const_reference first() const { return *this; } | ||||
| @@ -290,7 +331,9 @@ public: | ||||
|             compressed_pair_5() : _first(), _second() {} | ||||
|             compressed_pair_5(first_param_type x, second_param_type y) : _first(x), _second(y) {} | ||||
|    // only one single argument constructor since T1 == T2 | ||||
|    explicit compressed_pair_5(first_param_type x) : _first(x), _second() {} | ||||
|    explicit compressed_pair_5(first_param_type x) : _first(x), _second(x) {} | ||||
|    compressed_pair_5(const ::boost::compressed_pair<T1,T2>& c)  | ||||
|       : _first(c.first()), _second(c.second()) {} | ||||
|  | ||||
|    first_reference       first()       { return _first; } | ||||
|    first_const_reference first() const { return _first; } | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| //  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. | ||||
| //  (C) Copyright David Abrahams, Jeremy Siek, and Daryle Walker 1999-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 | ||||
| //  29 May 01 Added operator classes for << and >>.  Added input and output | ||||
| //            iterator helper classes.  Added classes to connect equality and | ||||
| //            relational operators.  Added classes for groups of related | ||||
| //            operators.  Reimplemented example operator and iterator helper | ||||
| //            classes in terms of the new groups.  (Daryle Walker, with help | ||||
| //            from Alexy Gurtovoy) | ||||
| //  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 | ||||
| @@ -280,12 +282,190 @@ struct indexable : B | ||||
|   } | ||||
| }; | ||||
|  | ||||
| //  More operator classes (contributed by Daryle Walker) --------------------// | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct left_shiftable2 : B | ||||
| { | ||||
|      friend T operator<<(T x, const U& y) { return x <<= y; } | ||||
| }; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct left_shiftable1 : B | ||||
| { | ||||
|      friend T operator<<(T x, const T& y) { return x <<= y; } | ||||
| }; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct right_shiftable2 : B | ||||
| { | ||||
|      friend T operator>>(T x, const U& y) { return x >>= y; } | ||||
| }; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct right_shiftable1 : B | ||||
| { | ||||
|      friend T operator>>(T x, const T& y) { return x >>= y; } | ||||
| }; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct equivalent2 : B | ||||
| { | ||||
|   friend bool operator==(const T& x, const U& y) | ||||
|   { | ||||
|     return !(x < y) && !(x > y); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct equivalent1 : B | ||||
| { | ||||
|   friend bool operator==(const T&x, const T&y) | ||||
|   { | ||||
|     return !(x < y) && !(y < x); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct partially_ordered2 : B | ||||
| { | ||||
|   friend bool operator<=(const T& x, const U& y) | ||||
|     { return (x < y) || (x == y); } | ||||
|   friend bool operator>=(const T& x, const U& y) | ||||
|     { return (x > y) || (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) || (y == x); } | ||||
|   friend bool operator>=(const U& x, const T& y) | ||||
|     { return (y < x) || (y == x); } | ||||
| }; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct partially_ordered1 : B | ||||
| { | ||||
|   friend bool operator>(const T& x, const T& y) | ||||
|     { return y < x; } | ||||
|   friend bool operator<=(const T& x, const T& y) | ||||
|     { return (x < y) || (x == y); } | ||||
|   friend bool operator>=(const T& x, const T& y) | ||||
|     { return (y < x) || (x == y); } | ||||
| }; | ||||
|  | ||||
| //  Combined operator classes (contributed by Daryle Walker) ----------------// | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct totally_ordered2 | ||||
|     : less_than_comparable2<T, U | ||||
|     , equality_comparable2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct totally_ordered1 | ||||
|     : less_than_comparable1<T | ||||
|     , equality_comparable1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct additive2 | ||||
|     : addable2<T, U | ||||
|     , subtractable2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct additive1 | ||||
|     : addable1<T | ||||
|     , subtractable1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct multiplicative2 | ||||
|     : multipliable2<T, U | ||||
|     , dividable2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct multiplicative1 | ||||
|     : multipliable1<T | ||||
|     , dividable1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct integer_multiplicative2 | ||||
|     : multiplicative2<T, U | ||||
|     , modable2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct integer_multiplicative1 | ||||
|     : multiplicative1<T | ||||
|     , modable1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct arithmetic2 | ||||
|     : additive2<T, U | ||||
|     , multiplicative2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct arithmetic1 | ||||
|     : additive1<T | ||||
|     , multiplicative1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct integer_arithmetic2 | ||||
|     : additive2<T, U | ||||
|     , integer_multiplicative2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct integer_arithmetic1 | ||||
|     : additive1<T | ||||
|     , integer_multiplicative1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct bitwise2 | ||||
|     : xorable2<T, U | ||||
|     , andable2<T, U | ||||
|     , orable2<T, U, B | ||||
|       > > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct bitwise1 | ||||
|     : xorable1<T | ||||
|     , andable1<T | ||||
|     , orable1<T, B | ||||
|       > > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct unit_steppable | ||||
|     : incrementable<T | ||||
|     , decrementable<T, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class U, class B = ::boost::detail::empty_base> | ||||
| struct shiftable2 | ||||
|     : left_shiftable2<T, U | ||||
|     , right_shiftable2<T, U, B | ||||
|       > > {}; | ||||
|  | ||||
| template <class T, class B = ::boost::detail::empty_base> | ||||
| struct shiftable1 | ||||
|     : left_shiftable1<T | ||||
|     , right_shiftable1<T, B | ||||
|       > > {}; | ||||
|  | ||||
| #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE | ||||
| } // namespace boost | ||||
| #endif // BOOST_NO_OPERATORS_IN_NAMESPACE | ||||
|  | ||||
|  | ||||
| // BOOST_IMPORT_TEMPLATE1/BOOST_IMPORT_TEMPLATE2 - | ||||
| // BOOST_IMPORT_TEMPLATE1 .. BOOST_IMPORT_TEMPLATE3 - | ||||
| // | ||||
| // 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 | ||||
| @@ -293,12 +473,31 @@ struct indexable : B | ||||
| // two-argument forms. Note that these macros expect to be invoked from within | ||||
| // boost. | ||||
|  | ||||
| #if defined(BOOST_NO_OPERATORS_IN_NAMESPACE) | ||||
| #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE | ||||
|  | ||||
| #  if defined(BOOST_NO_USING_TEMPLATE) | ||||
|   // The template is already in boost so we have nothing to do. | ||||
| # define BOOST_IMPORT_TEMPLATE3(template_name) | ||||
| # define BOOST_IMPORT_TEMPLATE2(template_name) | ||||
| # define BOOST_IMPORT_TEMPLATE1(template_name) | ||||
|  | ||||
| #else // BOOST_NO_OPERATORS_IN_NAMESPACE | ||||
|  | ||||
| #  ifndef BOOST_NO_USING_TEMPLATE | ||||
|  | ||||
|      // Bring the names in with a using-declaration | ||||
|      // to avoid stressing the compiler. | ||||
| #    define BOOST_IMPORT_TEMPLATE3(template_name) using ::template_name; | ||||
| #    define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name; | ||||
| #    define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name; | ||||
|  | ||||
| #  else | ||||
|  | ||||
|      // Otherwise, 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_TEMPLATE3(template_name)                                 \ | ||||
|      template <class T, class U, class V, class B = ::boost::detail::empty_base>  \ | ||||
|      struct template_name : ::template_name<T, U, V, B> {}; | ||||
|  | ||||
|      // 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> {}; | ||||
| @@ -307,21 +506,8 @@ struct indexable : B | ||||
|      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 | ||||
|  | ||||
| // | ||||
| @@ -330,7 +516,7 @@ struct indexable : B | ||||
| // the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as | ||||
| // neccessary. | ||||
| // | ||||
| #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
| #ifndef 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 | ||||
| @@ -353,6 +539,15 @@ template<class T> struct is_chained_base { | ||||
|  | ||||
| } // namespace boost | ||||
|  | ||||
| // Import a 3-type-argument operator template into boost (if neccessary) and | ||||
| // provide a specialization of 'is_chained_base<>' for it. | ||||
| # define BOOST_OPERATOR_TEMPLATE3(template_name3)                     \ | ||||
|   BOOST_IMPORT_TEMPLATE3(template_name3)                              \ | ||||
|   template<class T, class U, class V, class B>                        \ | ||||
|   struct is_chained_base< ::boost::template_name3<T, U, V, B> > {     \ | ||||
|     typedef ::boost::detail::true_t value;                            \ | ||||
|   }; | ||||
|  | ||||
| // 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)                  \ | ||||
| @@ -412,6 +607,8 @@ BOOST_OPERATOR_TEMPLATE1(template_name##1) | ||||
|  | ||||
| #else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|  | ||||
| #  define BOOST_OPERATOR_TEMPLATE3(template_name3) \ | ||||
|         BOOST_IMPORT_TEMPLATE3(template_name3) | ||||
| #  define BOOST_OPERATOR_TEMPLATE2(template_name2) \ | ||||
|         BOOST_IMPORT_TEMPLATE2(template_name2) | ||||
| #  define BOOST_OPERATOR_TEMPLATE1(template_name1) \ | ||||
| @@ -440,47 +637,41 @@ BOOST_OPERATOR_TEMPLATE(orable) | ||||
|  | ||||
| BOOST_OPERATOR_TEMPLATE1(incrementable) | ||||
| BOOST_OPERATOR_TEMPLATE1(decrementable) | ||||
|  | ||||
| BOOST_OPERATOR_TEMPLATE2(dereferenceable) | ||||
| BOOST_OPERATOR_TEMPLATE3(indexable) | ||||
|  | ||||
| // 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 | ||||
| BOOST_OPERATOR_TEMPLATE(left_shiftable) | ||||
| BOOST_OPERATOR_TEMPLATE(right_shiftable) | ||||
| BOOST_OPERATOR_TEMPLATE(equivalent) | ||||
| BOOST_OPERATOR_TEMPLATE(partially_ordered) | ||||
|  | ||||
| #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 | ||||
| BOOST_OPERATOR_TEMPLATE(totally_ordered) | ||||
| BOOST_OPERATOR_TEMPLATE(additive) | ||||
| BOOST_OPERATOR_TEMPLATE(multiplicative) | ||||
| BOOST_OPERATOR_TEMPLATE(integer_multiplicative) | ||||
| BOOST_OPERATOR_TEMPLATE(arithmetic) | ||||
| BOOST_OPERATOR_TEMPLATE(integer_arithmetic) | ||||
| BOOST_OPERATOR_TEMPLATE(bitwise) | ||||
| BOOST_OPERATOR_TEMPLATE1(unit_steppable) | ||||
| BOOST_OPERATOR_TEMPLATE(shiftable) | ||||
|  | ||||
| #undef BOOST_OPERATOR_TEMPLATE | ||||
| #undef BOOST_OPERATOR_TEMPLATE3 | ||||
| #undef BOOST_OPERATOR_TEMPLATE2 | ||||
| #undef BOOST_OPERATOR_TEMPLATE1 | ||||
| #undef BOOST_IMPORT_TEMPLATE1 | ||||
| #undef BOOST_IMPORT_TEMPLATE2 | ||||
| #undef BOOST_IMPORT_TEMPLATE3 | ||||
|  | ||||
| // 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 | ||||
|       > > > > > > > > > > {}; | ||||
|     : totally_ordered2<T,U | ||||
|     , integer_arithmetic2<T,U | ||||
|     , bitwise2<T,U | ||||
|       > > > {}; | ||||
|  | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
| template <class T, class U = T> | ||||
| @@ -490,31 +681,47 @@ 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 | ||||
|       > > > > > > > > > > > > {}; | ||||
|     : totally_ordered<T | ||||
|     , integer_arithmetic<T | ||||
|     , bitwise<T | ||||
|     , unit_steppable<T | ||||
|       > > > > {}; | ||||
|  | ||||
| //  Iterator helper classes (contributed by Jeremy Siek) -------------------// | ||||
| //  (Input and output iterator helpers contributed by Daryle Walker) -------// | ||||
| //  (Changed to use combined operator classes by Daryle Walker) ------------// | ||||
| template <class T, | ||||
|           class V, | ||||
|           class D = std::ptrdiff_t, | ||||
|           class P = V const *, | ||||
|           class R = V const &> | ||||
| struct input_iterator_helper | ||||
|   : equality_comparable1<T | ||||
|   , incrementable<T | ||||
|   , dereferenceable<T, P | ||||
|   , boost::iterator<std::input_iterator_tag, V, D, P, R | ||||
|     > > > > {}; | ||||
| #ifndef BOOST_MSVC | ||||
| template <class T, | ||||
|           class V = void, | ||||
|           class D = void, | ||||
|           class P = void, | ||||
|           class R = void> | ||||
| struct output_iterator_helper | ||||
|   : incrementable<T | ||||
|   , boost::iterator<std::output_iterator_tag, V, D, P, R | ||||
|     > > {}; | ||||
| #endif | ||||
| template <class T, | ||||
|           class V, | ||||
|           class D = std::ptrdiff_t, | ||||
|           class P = V*, | ||||
|           class R = V&> | ||||
| struct forward_iterator_helper | ||||
|   : equality_comparable<T | ||||
|   : equality_comparable1<T | ||||
|   , incrementable<T | ||||
|   , dereferenceable<T,P | ||||
|   , boost::iterator<std::forward_iterator_tag, V, D | ||||
|   , dereferenceable<T, P | ||||
|   , boost::iterator<std::forward_iterator_tag, V, D, P, R | ||||
|     > > > > {}; | ||||
|  | ||||
| template <class T, | ||||
| @@ -523,12 +730,11 @@ template <class 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 | ||||
|     > > > > > {}; | ||||
|   : equality_comparable1<T | ||||
|   , unit_steppable<T | ||||
|   , dereferenceable<T, P | ||||
|   , boost::iterator<std::bidirectional_iterator_tag, V, D, P, R | ||||
|     > > > > {}; | ||||
|  | ||||
| template <class T, | ||||
|           class V,  | ||||
| @@ -536,22 +742,17 @@ template <class 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 | ||||
|     > > > > > > > > > | ||||
|   : totally_ordered1<T | ||||
|   , unit_steppable<T | ||||
|   , dereferenceable<T, P | ||||
|   , additive2<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 | ||||
|   | ||||
| @@ -11,6 +11,9 @@ | ||||
| //  Classes appear in alphabetical order | ||||
|  | ||||
| //  Revision History | ||||
| //  21 May 01  checked_delete() and checked_array_delete() added (Beman Dawes, | ||||
| //             suggested by Dave Abrahams, generalizing idea from Vladimir Prus) | ||||
| //  21 May 01  made next() and prior() inline (Beman Dawes)   | ||||
| //  26 Jan 00  protected noncopyable destructor added (Miki Jovanovic) | ||||
| //  10 Dec 99  next() and prior() templates added (Dave Abrahams) | ||||
| //  30 Aug 99  moved cast templates to cast.hpp (Beman Dawes) | ||||
| @@ -22,12 +25,32 @@ | ||||
| #ifndef BOOST_UTILITY_HPP | ||||
| #define BOOST_UTILITY_HPP | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <cstddef>            // for size_t | ||||
| #include <utility>            // for std::pair | ||||
| #include <boost/config.hpp>        // broken compiler workarounds  | ||||
| #include <boost/static_assert.hpp>  | ||||
| #include <cstddef>                 // for size_t | ||||
| #include <utility>                 // for std::pair | ||||
|  | ||||
| namespace boost | ||||
| { | ||||
| //  checked_delete() and checked_array_delete()  -----------------------------// | ||||
|  | ||||
|     // verify that types are complete for increased safety | ||||
|  | ||||
|     template< typename T > | ||||
|     inline void checked_delete(T * x) | ||||
|     { | ||||
|         BOOST_STATIC_ASSERT( sizeof(T) != 0 ); // assert type complete at point | ||||
|                                                // of instantiation | ||||
|         delete x; | ||||
|     } | ||||
|  | ||||
|     template< typename T > | ||||
|     inline void checked_array_delete(T  * x) | ||||
|     { | ||||
|         BOOST_STATIC_ASSERT( sizeof(T) != 0 ); // assert type complete at point | ||||
|                                                // of instantiation | ||||
|         delete [] x; | ||||
|     } | ||||
|  | ||||
| //  next() and prior() template functions  -----------------------------------// | ||||
|  | ||||
| @@ -41,10 +64,10 @@ namespace boost | ||||
|     //  Contributed by Dave Abrahams | ||||
|  | ||||
|     template <class T> | ||||
|     T next(T x) { return ++x; } | ||||
|     inline T next(T x) { return ++x; } | ||||
|  | ||||
|     template <class T> | ||||
|     T prior(T x) { return --x; } | ||||
|     inline T prior(T x) { return --x; } | ||||
|  | ||||
|  | ||||
| //  class noncopyable  -------------------------------------------------------// | ||||
|   | ||||
							
								
								
									
										443
									
								
								indirect_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										443
									
								
								indirect_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,443 @@ | ||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> | ||||
|  | ||||
| <html> | ||||
| <head> | ||||
|     <meta name="generator" content="HTML Tidy, see www.w3.org"> | ||||
|     <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
|     <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
|     <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
|  | ||||
|     <title>Indirect Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
| 	 | ||||
|     <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align= | ||||
|     "center" width="277" height="86">  | ||||
|  | ||||
|     <h1>Indirect Iterator Adaptor</h1> | ||||
|     Defined in header <a href= | ||||
|     "../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>  | ||||
|  | ||||
|     <p>The indirect iterator adaptor augments an iterator by applying an | ||||
|     <b>extra</b> dereference inside of <tt>operator*()</tt>. For example, this | ||||
|     iterator makes it possible to view a container of pointers or | ||||
|     smart-pointers (e.g. <tt>std::list<boost::shared_ptr<foo> | ||||
|     ></tt>) as if it were a container of the pointed-to type. The following | ||||
|     <b>pseudo-code</b> shows the basic idea of the indirect iterator: | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| // inside a hypothetical indirect_iterator class... | ||||
| typedef std::iterator_traits<BaseIterator>::value_type Pointer; | ||||
| typedef std::iterator_traits<Pointer>::reference reference; | ||||
|  | ||||
| reference indirect_iterator::operator*() const { | ||||
|   return **this->base_iterator; | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h2>Synopsis</h2> | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class BaseIterator, | ||||
|             class Value, class Reference, class Category, class Pointer> | ||||
|   struct indirect_iterator_generator; | ||||
|    | ||||
|   template <class BaseIterator, | ||||
|             class Value, class Reference, class ConstReference,  | ||||
|             class Category, class Pointer, class ConstPointer> | ||||
|   struct indirect_iterator_pair_generator; | ||||
|  | ||||
|   template <class BaseIterator> | ||||
|   typename indirect_iterator_generator<BaseIterator>::type | ||||
|   make_indirect_iterator(BaseIterator base)   | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     <hr> | ||||
|  | ||||
|     <h2><a name="indirect_iterator_generator">The Indirect Iterator Type | ||||
|     Generator</a></h2> | ||||
|     The <tt>indirect_iterator_generator</tt> template is a <a href= | ||||
|     "../../more/generic_programming.html#type_generator">generator</a> of | ||||
|     indirect iterator types. The main template parameter for this class is the | ||||
|     <tt>BaseIterator</tt> type that is being wrapped. In most cases the type of | ||||
|     the elements being pointed to can be deduced using | ||||
|     <tt>std::iterator_traits</tt>, but in some situations the user may want to | ||||
|     override this type, so there are also template parameters that allow a user | ||||
|     to control the <tt>value_type</tt>, <tt>pointer</tt>, and | ||||
|     <tt>reference</tt> types of the resulting iterators.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class BaseIterator, | ||||
|           class Value, class Reference, class Pointer> | ||||
| class indirect_iterator_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href= | ||||
| "./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting indirect iterator type  | ||||
| }; | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|     This example uses the <tt>indirect_iterator_generator</tt> to create | ||||
|     indirect iterators which dereference the pointers stored in the | ||||
|     <tt>pointers_to_chars</tt> array to access the <tt>char</tt>s in the | ||||
|     <tt>characters</tt> array.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| #include <boost/config.hpp> | ||||
| #include <vector> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   char characters[] = "abcdefg"; | ||||
|   const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char | ||||
|   char* pointers_to_chars[N];                        // at the end. | ||||
|   for (int i = 0; i < N; ++i) | ||||
|     pointers_to_chars[i] = &characters[i]; | ||||
|    | ||||
|   boost::indirect_iterator_generator<char**, char>::type  | ||||
|     indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); | ||||
|  | ||||
|   std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   // to be continued... | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Template Parameters</h3> | ||||
|  | ||||
|     <table border> | ||||
|       <tr> | ||||
|         <th>Parameter | ||||
|  | ||||
|         <th>Description | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>BaseIterator</tt>  | ||||
|  | ||||
|         <td>The iterator type being wrapped. The <tt>value_type</tt> | ||||
|         of the base iterator should itself be dereferenceable.   | ||||
|         The return type of the <tt>operator*</tt> for the | ||||
|         <tt>value_type</tt> should match the <tt>Reference</tt> type. | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Value</tt>  | ||||
|  | ||||
|         <td>The <tt>value_type</tt> of the resulting iterator, unless const. If | ||||
|         Value is <tt>const X</tt>, a conforming compiler makes the | ||||
|         <tt>value_type</tt> <tt><i>non-</i>const X</tt><a href= | ||||
|         "iterator_adaptors.htm#1">[1]</a>. Note that if the default | ||||
|          is used for <tt>Value</tt>, then there must be a valid specialization | ||||
|          of <tt>iterator_traits</tt> for the value type of the base iterator. | ||||
|          <br> | ||||
|          <b>Default:</b> <tt>std::iterator_traits<<br> | ||||
|          <20> std::iterator_traits<BaseIterator>::value_type | ||||
|         >::value_type</tt><a href="#2">[2]</a>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Reference</tt>  | ||||
|  | ||||
|         <td>The <tt>reference</tt> type of the resulting iterator, and in | ||||
|         particular, the result type of <tt>operator*()</tt>.<br> | ||||
|          <b>Default:</b> <tt>Value&</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Pointer</tt>  | ||||
|  | ||||
|         <td>The <tt>pointer</tt> type of the resulting iterator, and in | ||||
|         particular, the result type of <tt>operator->()</tt>.<br> | ||||
|          <b>Default:</b> <tt>Value*</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Category</tt>  | ||||
|         <td>The <tt>iterator_category</tt> type for the resulting iterator.<br> | ||||
|          <b>Default:</b> | ||||
|         <tt>std::iterator_traits<BaseIterator>::iterator_category</tt>  | ||||
|  | ||||
|     </table> | ||||
|  | ||||
|     <h3>Concept Model</h3> | ||||
|     The indirect iterator will model whichever <a href= | ||||
|     "http://www.sgi.com/tech/stl/Iterators.html">standard iterator | ||||
|     concept category</a> is modeled by the base iterator. Thus, if the | ||||
|     base iterator is a model of <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
|     Access Iterator</a> then so is the resulting indirect iterator. If | ||||
|     the base iterator models a more restrictive concept, the resulting | ||||
|     indirect iterator will model the same concept <a href="#3">[3]</a>. | ||||
|  | ||||
|     <h3>Members</h3> | ||||
|     The indirect iterator type implements the member functions and operators | ||||
|     required of the <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access | ||||
|     Iterator</a> concept. In addition it has the following constructor:  | ||||
| <pre> | ||||
| explicit indirect_iterator_generator::type(const BaseIterator& it) | ||||
| </pre> | ||||
|     <br> | ||||
|      <br> | ||||
|       | ||||
|     <hr> | ||||
|  | ||||
|     <p> | ||||
|  | ||||
|     <h2><a name="indirect_iterator_pair_generator">The Indirect Iterator Pair | ||||
|     Generator</a></h2> | ||||
|     Sometimes a pair of <tt>const</tt>/non-<tt>const</tt> pair of iterators is | ||||
|     needed, such as when implementing a container. The | ||||
|     <tt>indirect_iterator_pair_generator</tt> class makes it more convenient to | ||||
|     create this pair of iterator types.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class BaseIterator, | ||||
|           class Value, class Pointer, class Reference, | ||||
|           class ConstPointer, class ConstReference> | ||||
| class indirect_iterator_pair_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href= | ||||
| "./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> iterator;       // the mutable indirect iterator type  | ||||
|   typedef <tt><a href= | ||||
| "./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> const_iterator; // the immutable indirect iterator type  | ||||
| }; | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
|   // continuing from the last example... | ||||
|  | ||||
|   typedef boost::indirect_iterator_pair_generator<char**, | ||||
|     char, char*, char&, const char*, const char&> PairGen; | ||||
|  | ||||
|   char mutable_characters[N]; | ||||
|   char* pointers_to_mutable_chars[N]; | ||||
|   for (int i = 0; i < N; ++i) | ||||
|     pointers_to_mutable_chars[i] = &mutable_characters[i]; | ||||
|  | ||||
|   PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars), | ||||
|     mutable_indirect_last(pointers_to_mutable_chars + N); | ||||
|   PairGen::const_iterator const_indirect_first(pointers_to_chars), | ||||
|     const_indirect_last(pointers_to_chars + N); | ||||
|  | ||||
|   std::transform(const_indirect_first, const_indirect_last, | ||||
|      mutable_indirect_first, std::bind1st(std::plus<char>(), 1)); | ||||
|  | ||||
|   std::copy(mutable_indirect_first, mutable_indirect_last, | ||||
|       std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|   // to be continued... | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <p>The output is: | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| b,c,d,e,f,g,h, | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Template Parameters</h3> | ||||
|  | ||||
|     <table border> | ||||
|       <tr> | ||||
|         <th>Parameter | ||||
|  | ||||
|         <th>Description | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>BaseIterator</tt>  | ||||
|  | ||||
|         <td>The iterator type being wrapped. The <tt>value_type</tt> of the | ||||
|         base iterator should itself be dereferenceable. | ||||
|         The return type of the <tt>operator*</tt> for the | ||||
|         <tt>value_type</tt> should match the <tt>Reference</tt> type. | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Value</tt>  | ||||
|  | ||||
|         <td>The <tt>value_type</tt> of the resulting iterators. | ||||
|          If Value is <tt>const X</tt>, a conforming compiler makes the | ||||
|          <tt>value_type</tt> <tt><i>non-</i>const X</tt><a href= | ||||
|          "iterator_adaptors.htm#1">[1]</a>. Note that if the default | ||||
|          is used for <tt>Value</tt>, then there must be a valid | ||||
|          specialization of <tt>iterator_traits</tt> for the value type | ||||
|          of the base iterator.<br> | ||||
|  | ||||
|          <b>Default:</b> <tt>std::iterator_traits<<br> | ||||
|          <20> std::iterator_traits<BaseIterator>::value_type | ||||
|         >::value_type</tt><a href="#2">[2]</a>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Reference</tt>  | ||||
|  | ||||
|         <td>The <tt>reference</tt> type of the resulting <tt>iterator</tt>, and | ||||
|         in particular, the result type of its <tt>operator*()</tt>.<br> | ||||
|          <b>Default:</b> <tt>Value&</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Pointer</tt>  | ||||
|  | ||||
|         <td>The <tt>pointer</tt> type of the resulting <tt>iterator</tt>, and | ||||
|         in particular, the result type of its <tt>operator->()</tt>.<br> | ||||
|          <b>Default:</b> <tt>Value*</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>ConstReference</tt>  | ||||
|  | ||||
|         <td>The <tt>reference</tt> type of the resulting | ||||
|         <tt>const_iterator</tt>, and in particular, the result type of its | ||||
|         <tt>operator*()</tt>.<br> | ||||
|          <b>Default:</b> <tt>const Value&</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>ConstPointer</tt>  | ||||
|  | ||||
|         <td>The <tt>pointer</tt> type of the resulting <tt>const_iterator</tt>, | ||||
|         and in particular, the result type of its <tt>operator->()</tt>.<br> | ||||
|          <b>Default:</b> <tt>const Value*</tt>  | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Category</tt>  | ||||
|         <td>The <tt>iterator_category</tt> type for the resulting iterator.<br> | ||||
|          <b>Default:</b> | ||||
|         <tt>std::iterator_traits<BaseIterator>::iterator_category</tt>  | ||||
|     </table> | ||||
|  | ||||
|     <h3>Concept Model</h3> | ||||
|  | ||||
|     The indirect iterators will model whichever <a href= | ||||
|     "http://www.sgi.com/tech/stl/Iterators.html">standard iterator | ||||
|     concept category</a> is modeled by the base iterator. Thus, if the | ||||
|     base iterator is a model of <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
|     Access Iterator</a> then so are the resulting indirect | ||||
|     iterators. If the base iterator models a more restrictive concept, | ||||
|     the resulting indirect iterators will model the same concept <a | ||||
|     href="#3">[3]</a>. | ||||
|  | ||||
|  | ||||
|     <h3>Members</h3> | ||||
|     The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types implement | ||||
|     the member functions and operators required of the <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access | ||||
|     Iterator</a> concept. In addition they support the following constructors:  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| explicit indirect_iterator_pair_generator::iterator(const BaseIterator& it) | ||||
| explicit indirect_iterator_pair_generator::const_iterator(const BaseIterator& it) | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     <br> | ||||
|      <br> | ||||
|       | ||||
|     <hr> | ||||
|  | ||||
|     <p> | ||||
|  | ||||
|     <h2><a name="make_indirect_iterator">The Indirect Iterator Object | ||||
|     Generator</a></h2> | ||||
|     The <tt>make_indirect_iterator()</tt> function provides a more convenient | ||||
|     way to create indirect iterator objects. The function saves the user the | ||||
|     trouble of explicitly writing out the iterator types.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class BaseIterator> | ||||
| typename indirect_iterator_generator<BaseIterator>::type | ||||
| make_indirect_iterator(BaseIterator base)   | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|     Here we again print the <tt>char</tt>s from the array <tt>characters</tt> | ||||
|     by accessing them through the array of pointers <tt>pointer_to_chars</tt>, | ||||
|     but this time we use the <tt>make_indirect_iterator()</tt> function which | ||||
|     saves us some typing.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
|   // continuing from the last example... | ||||
|  | ||||
|   std::copy(boost::make_indirect_iterator(pointers_to_chars),  | ||||
|       boost::make_indirect_iterator(pointers_to_chars + N), | ||||
|       std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     The output is:  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| a,b,c,d,e,f,g, | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     <hr> | ||||
|  | ||||
|     <h3>Notes</h3> | ||||
|  | ||||
|     <p> | ||||
|  | ||||
|     <p><a name="2">[2]</a> If your compiler does not support partial | ||||
|     specialization and the base iterator or its <tt>value_type</tt> is a | ||||
|     builtin pointer type, you will not be able to use the default for | ||||
|     <tt>Value</tt> and will need to specify this type explicitly. | ||||
|  | ||||
|     <p><a name="3">[3]</a>There is a caveat to which concept the | ||||
|     indirect iterator can model.  If the return type of the | ||||
|     <tt>operator*</tt> for the base iterator's value type is not a | ||||
|     true reference, then strickly speaking, the indirect iterator can | ||||
|     not be a model of <a href= | ||||
|     "http://www.sgi.com/tech/stl/ForwardIterator.html">Forward | ||||
|     Iterator</a> or any of the concepts that refine it. In this case | ||||
|     the <tt>Category</tt> for the indirect iterator should be | ||||
|     specified as <tt>std::input_iterator_tag</tt>. However, even in | ||||
|     this case, if the base iterator is a random access iterator, the | ||||
|     resulting indirect iterator will still satisfy most of the | ||||
|     requirements for <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
|     Access Iterator</a>. | ||||
|      | ||||
|     <hr> | ||||
|  | ||||
|     <p>Revised  | ||||
|     <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --> | ||||
|  | ||||
|  | ||||
|     <p>© Copyright Jeremy Siek and David Abrahams 2001. Permission to | ||||
|     copy, use, modify, sell and distribute this document is granted provided | ||||
|     this copyright notice appears in all copies. This document is provided "as | ||||
|     is" without express or implied warranty, and with no claim as to its | ||||
|     suitability for any purpose.  | ||||
|     <!--  LocalWords:  html charset alt gif hpp BaseIterator const namespace struct | ||||
|              --> | ||||
|       | ||||
|     <!--  LocalWords:  ConstPointer ConstReference typename iostream int abcdefg | ||||
|              --> | ||||
|      <!--  LocalWords:  sizeof  PairGen pre Jeremy Siek David Abrahams | ||||
|              --> | ||||
|  | ||||
|  | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										60
									
								
								indirect_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								indirect_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| // (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears | ||||
| // in all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <vector> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <functional> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   char characters[] = "abcdefg"; | ||||
|   const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char | ||||
|   char* pointers_to_chars[N];                        // at the end. | ||||
|   for (int i = 0; i < N; ++i) | ||||
|     pointers_to_chars[i] = &characters[i]; | ||||
|  | ||||
|   // Example of using indirect_iterator_generator | ||||
|    | ||||
|   boost::indirect_iterator_generator<char**, char>::type  | ||||
|     indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); | ||||
|  | ||||
|   std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|  | ||||
|   // Example of using indirect_iterator_pair_generator | ||||
|  | ||||
|   typedef boost::indirect_iterator_pair_generator<char**, char> PairGen; | ||||
|  | ||||
|   char mutable_characters[N]; | ||||
|   char* pointers_to_mutable_chars[N]; | ||||
|   for (int i = 0; i < N; ++i) | ||||
|     pointers_to_mutable_chars[i] = &mutable_characters[i]; | ||||
|  | ||||
|   PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars), | ||||
|     mutable_indirect_last(pointers_to_mutable_chars + N); | ||||
|   PairGen::const_iterator const_indirect_first(pointers_to_chars), | ||||
|     const_indirect_last(pointers_to_chars + N); | ||||
|  | ||||
|   std::transform(const_indirect_first, const_indirect_last, | ||||
| 		 mutable_indirect_first, std::bind1st(std::plus<char>(), 1)); | ||||
|  | ||||
|   std::copy(mutable_indirect_first, mutable_indirect_last, | ||||
| 	    std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|    | ||||
|   // Example of using make_indirect_iterator() | ||||
|  | ||||
|   std::copy(boost::make_indirect_iterator(pointers_to_chars),  | ||||
| 	    boost::make_indirect_iterator(pointers_to_chars + N), | ||||
| 	    std::ostream_iterator<char>(std::cout, ",")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										151
									
								
								indirect_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								indirect_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  Revision History | ||||
| //  08 Mar 2001   Jeremy Siek | ||||
| //       Moved test of indirect iterator into its own file. It to | ||||
| //       to be in iterator_adaptor_test.cpp. | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
|  | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
| #include <boost/pending/iterator_tests.hpp> | ||||
| #include <boost/concept_archetype.hpp> | ||||
| #include <stdlib.h> | ||||
| #include <deque> | ||||
| #include <set> | ||||
|  | ||||
| struct my_iterator_tag : public std::random_access_iterator_tag { }; | ||||
|  | ||||
| using boost::dummyT; | ||||
|  | ||||
| typedef std::deque<int> storage; | ||||
| typedef std::deque<int*> pointer_deque; | ||||
| typedef std::set<storage::iterator> iterator_set; | ||||
|  | ||||
| void more_indirect_iterator_tests() | ||||
| { | ||||
| // For some reason all heck breaks loose in the compiler under these conditions. | ||||
| #if !defined(BOOST_MSVC) || !defined(__STL_DEBUG) | ||||
|     storage store(1000); | ||||
|     std::generate(store.begin(), store.end(), rand); | ||||
|      | ||||
|     pointer_deque ptr_deque; | ||||
|     iterator_set iter_set; | ||||
|  | ||||
|     for (storage::iterator p = store.begin(); p != store.end(); ++p) | ||||
|     { | ||||
|         ptr_deque.push_back(&*p); | ||||
|         iter_set.insert(p); | ||||
|     } | ||||
|  | ||||
|     typedef boost::indirect_iterator_pair_generator< | ||||
|         pointer_deque::iterator | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , int | ||||
| #endif | ||||
|     > IndirectDeque; | ||||
|  | ||||
|     IndirectDeque::iterator db(ptr_deque.begin()); | ||||
|     IndirectDeque::iterator de(ptr_deque.end()); | ||||
|     assert(static_cast<std::size_t>(de - db) == store.size()); | ||||
|     assert(db + store.size() == de); | ||||
|     IndirectDeque::const_iterator dci(db); | ||||
|     assert(db == dci); | ||||
|     assert(dci == db); | ||||
|     assert(dci != de); | ||||
|     assert(dci < de); | ||||
|     assert(dci <= de); | ||||
|     assert(de >= dci); | ||||
|     assert(de > dci); | ||||
|     dci = de; | ||||
|     assert(dci == de); | ||||
|  | ||||
|     boost::random_access_iterator_test(db + 1, store.size() - 1, boost::next(store.begin())); | ||||
|      | ||||
|     *db = 999; | ||||
|     assert(store.front() == 999); | ||||
|  | ||||
|     // Borland C++ is getting very confused about the typedef's here | ||||
|  | ||||
|     typedef boost::indirect_iterator_generator< | ||||
|         iterator_set::iterator | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , int | ||||
| #endif | ||||
|         >::type indirect_set_iterator; | ||||
|  | ||||
|     typedef boost::indirect_iterator_generator< | ||||
|         iterator_set::iterator, | ||||
|         const int | ||||
|         >::type const_indirect_set_iterator; | ||||
|  | ||||
|     indirect_set_iterator sb(iter_set.begin()); | ||||
|     indirect_set_iterator se(iter_set.end()); | ||||
|     const_indirect_set_iterator sci(iter_set.begin()); | ||||
|     assert(sci == sb); | ||||
|     assert(sci != se); | ||||
|     sci = se; | ||||
|     assert(sci == se); | ||||
|      | ||||
|     *boost::prior(se) = 888; | ||||
|     assert(store.back() == 888); | ||||
|     assert(std::equal(sb, se, store.begin())); | ||||
|  | ||||
|     boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]); | ||||
|     assert(std::equal(db, de, store.begin())); | ||||
|  | ||||
| #endif     | ||||
| } | ||||
|  | ||||
| int | ||||
| main() | ||||
| { | ||||
|   dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),  | ||||
|                      dummyT(3), dummyT(4), dummyT(5) }; | ||||
|   const int N = sizeof(array)/sizeof(dummyT); | ||||
|  | ||||
|   // Test indirect_iterator_generator | ||||
|   { | ||||
|     dummyT* ptr[N]; | ||||
|     for (int k = 0; k < N; ++k) | ||||
|       ptr[k] = array + k; | ||||
|  | ||||
|     typedef boost::indirect_iterator_generator<dummyT** | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , dummyT | ||||
| #endif | ||||
|       >::type indirect_iterator; | ||||
|  | ||||
|     typedef boost::indirect_iterator_generator<dummyT**, const dummyT>::type const_indirect_iterator; | ||||
|  | ||||
|     indirect_iterator i(ptr); | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|  | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|     boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array); | ||||
| #endif | ||||
|      | ||||
|     // check operator-> | ||||
|     assert((*i).m_x == i->foo()); | ||||
|  | ||||
|     const_indirect_iterator j(ptr); | ||||
|     boost::random_access_iterator_test(j, N, array); | ||||
|  | ||||
|     dummyT*const* const_ptr = ptr; | ||||
|      | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|     boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array); | ||||
| #endif | ||||
|     boost::const_nonconst_iterator_test(i, ++j); | ||||
|  | ||||
|     more_indirect_iterator_tests(); | ||||
|   } | ||||
|   std::cout << "test successful " << std::endl; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										27
									
								
								iter_adaptor_fail_expected1.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								iter_adaptor_fail_expected1.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| //  Test boost/pending/iterator_adaptors.hpp | ||||
|  | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| // Revision History | ||||
| // 21 Jan 01 Initial version (Jeremy Siek) | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <list> | ||||
| #include <boost/pending/iterator_adaptors.hpp> | ||||
|  | ||||
| int main() | ||||
| { | ||||
|   typedef boost::iterator_adaptor<std::list<int>::iterator, | ||||
|     boost::default_iterator_policies, | ||||
|     int,int&,int*,std::bidirectional_iterator_tag> adaptor_type; | ||||
|    | ||||
|   adaptor_type i; | ||||
|   i += 4; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										28
									
								
								iter_adaptor_fail_expected2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								iter_adaptor_fail_expected2.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| //  Test boost/pending/iterator_adaptors.hpp | ||||
|  | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| // Revision History | ||||
| // 21 Jan 01 Initial version (Jeremy Siek) | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <boost/pending/iterator_adaptors.hpp> | ||||
|  | ||||
| int main() | ||||
| { | ||||
|   typedef boost::iterator_adaptor<std::istream_iterator<int>, | ||||
|     boost::default_iterator_policies, | ||||
|     int,int&,int*,std::input_iterator_tag> adaptor_type; | ||||
|    | ||||
|   adaptor_type iter; | ||||
|   --iter; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										58
									
								
								iter_named_param_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								iter_named_param_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // (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. | ||||
|  | ||||
| // 27 June 2001 Jeremy Siek | ||||
| //     Upated for change in named params. | ||||
| // 8 Mar 2001   Jeremy Siek | ||||
| //     Initial checkin. | ||||
|  | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
| #include <boost/pending/iterator_tests.hpp> | ||||
| #include <boost/static_assert.hpp> | ||||
|  | ||||
| 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::reference_is<dummyT>, | ||||
|       boost::iterator_category_is<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::value_type_is<dummyT>, | ||||
|       boost::reference_is<const dummyT&>, | ||||
|       boost::pointer_is<const dummyT*>, | ||||
|       boost::iterator_category_is<std::forward_iterator_tag>, | ||||
|       boost::difference_type_is<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; | ||||
| } | ||||
| @@ -21,9 +21,8 @@ main(int, char*[]) | ||||
|   int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | ||||
|  | ||||
|   typedef std::binder1st< std::multiplies<int> > Function; | ||||
|   typedef boost::transform_iterator<Function, int*,  | ||||
|     boost::iterator<std::random_access_iterator_tag, int> | ||||
|   >::type doubling_iterator; | ||||
|   typedef boost::transform_iterator_generator<Function, 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)); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| //  Demonstrate and test boost/operators.hpp on std::iterators  -------------// | ||||
| //  Test boost/iterator_adaptors.hpp | ||||
|  | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| @@ -9,6 +9,37 @@ | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  27 June 01 Updated to changes in named parameters. | ||||
| //  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) | ||||
|  | ||||
| @@ -17,34 +48,19 @@ | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <functional> | ||||
| #include <boost/pending/iterator_adaptors.hpp> | ||||
|  | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
| #include <boost/pending/iterator_tests.hpp> | ||||
| #include <boost/pending/integer_range.hpp> | ||||
| #include <boost/concept_archetype.hpp> | ||||
| #include <cstdlib> | ||||
| #include <deque> | ||||
| #include <set> | ||||
|  | ||||
| struct my_iterator_tag : public std::random_access_iterator_tag { }; | ||||
|  | ||||
|  | ||||
| using boost::dummyT; | ||||
|  | ||||
| struct my_iter_traits { | ||||
|   typedef dummyT value_type; | ||||
|   typedef dummyT* pointer; | ||||
|   typedef dummyT& reference; | ||||
|   typedef my_iterator_tag iterator_category; | ||||
|   typedef std::ptrdiff_t difference_type; | ||||
| }; | ||||
|  | ||||
| struct my_const_iter_traits { | ||||
|   typedef dummyT value_type; | ||||
|   typedef const dummyT* pointer; | ||||
|   typedef const dummyT& reference; | ||||
|   typedef my_iterator_tag iterator_category; | ||||
|   typedef std::ptrdiff_t difference_type; | ||||
| }; | ||||
|  | ||||
| typedef boost::iterator_adaptors | ||||
|   <dummyT*, const dummyT*,  | ||||
|    my_iter_traits, my_const_iter_traits> My; | ||||
|  | ||||
| struct mult_functor { | ||||
|   typedef int result_type; | ||||
| @@ -71,6 +87,19 @@ struct select1st_ | ||||
|   } | ||||
| }; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| struct bar { }; | ||||
| void foo(bar) { } | ||||
|  | ||||
| int | ||||
| main() | ||||
| { | ||||
| @@ -81,88 +110,121 @@ main() | ||||
|   // sanity check, if this doesn't pass the test is buggy | ||||
|   boost::random_access_iterator_test(array,N,array); | ||||
|  | ||||
|   // Test the iterator_adaptors | ||||
|   // Check that the policy concept checks and the default policy | ||||
|   // implementation match up. | ||||
|   boost::function_requires<  | ||||
|      boost::RandomAccessIteratorPoliciesConcept< | ||||
|        boost::default_iterator_policies, int*, | ||||
|        boost::iterator<std::random_access_iterator_tag, int, std::ptrdiff_t, | ||||
|                       int*, int&> | ||||
|       > >(); | ||||
|  | ||||
|   // Test the iterator_adaptor | ||||
|   { | ||||
|     My::iterator i = array; | ||||
|     boost::iterator_adaptor<dummyT*, boost::default_iterator_policies, dummyT> i(array); | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|      | ||||
|     My::const_iterator j = array; | ||||
|     boost::iterator_adaptor<const dummyT*, boost::default_iterator_policies, const dummyT> j(array); | ||||
|     boost::random_access_iterator_test(j, N, array); | ||||
|     boost::const_nonconst_iterator_test(i, ++j); | ||||
|   } | ||||
|   // Test transform_iterator | ||||
|   { | ||||
|     int x[N], y[N]; | ||||
|     for (int k = 0; k < N; ++k) | ||||
|       x[k] = k; | ||||
|     std::copy(x, x + N, y); | ||||
|  | ||||
|     for (int k2 = 0; k2 < N; ++k2) | ||||
|       x[k2] = x[k2] * 2; | ||||
|  | ||||
|     boost::transform_iterator<mult_functor, int*, | ||||
|       boost::iterator<std::random_access_iterator_tag,int> >::type | ||||
|       i(y, mult_functor(2)); | ||||
|     boost::random_access_iterator_test(i, N, x); | ||||
|   } | ||||
|   // Test indirect_iterators | ||||
|   { | ||||
|     dummyT* ptr[N]; | ||||
|     for (int k = 0; k < N; ++k) | ||||
|       ptr[k] = array + k; | ||||
|     typedef boost::indirect_iterators<dummyT**, dummyT*, const dummyT*, | ||||
|       boost::iterator<std::random_access_iterator_tag, dummyT*>, | ||||
|       boost::iterator<std::random_access_iterator_tag, dummyT>, | ||||
|       boost::iterator<std::random_access_iterator_tag, const dummyT> | ||||
|       > Indirect; | ||||
|     Indirect::iterator i = ptr; | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|  | ||||
|     Indirect::const_iterator j = ptr; | ||||
|     boost::random_access_iterator_test(j, N, array); | ||||
|  | ||||
|     boost::const_nonconst_iterator_test(i, ++j);     | ||||
|   } | ||||
|   // Test projection_iterators | ||||
|   // 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_iterators<select1st_<Pair>, | ||||
|       Pair*, const Pair*, | ||||
|       boost::iterator<std::random_access_iterator_tag, Pair>, | ||||
|       boost::iterator<std::random_access_iterator_tag, const Pair> | ||||
|     typedef boost::projection_iterator_pair_generator<select1st_<Pair>, | ||||
|       Pair*, const Pair* | ||||
|       > Projection; | ||||
|      | ||||
|     Projection::iterator i = pair_array; | ||||
|     Projection::iterator i(pair_array); | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|  | ||||
|     Projection::const_iterator j = pair_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_iterators | ||||
|  | ||||
|   // Test reverse_iterator_generator | ||||
|   { | ||||
|     dummyT reversed[N]; | ||||
|     std::copy(array, array + N, reversed); | ||||
|     std::reverse(reversed, reversed + N); | ||||
|      | ||||
|     typedef boost::reverse_iterators<dummyT*, const dummyT*, | ||||
|       boost::iterator<std::random_access_iterator_tag,dummyT>, | ||||
|       boost::iterator<std::random_access_iterator_tag,const dummyT> | ||||
|       > Reverse; | ||||
|     Reverse::iterator i = reversed + N; | ||||
|     typedef boost::reverse_iterator_generator<dummyT* | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , dummyT | ||||
| #endif | ||||
|       >::type reverse_iterator; | ||||
|      | ||||
|     reverse_iterator i(reversed + N); | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|  | ||||
|     Reverse::const_iterator j = reversed + N; | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|     boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array); | ||||
| #endif | ||||
|  | ||||
|     typedef boost::reverse_iterator_generator<const dummyT* | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , const dummyT | ||||
| #endif | ||||
|       >::type const_reverse_iterator; | ||||
|      | ||||
|     const_reverse_iterator j(reversed + N); | ||||
|     boost::random_access_iterator_test(j, N, array); | ||||
|  | ||||
|     const dummyT* const_reversed = reversed; | ||||
|      | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|     boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array); | ||||
| #endif | ||||
|      | ||||
|     boost::const_nonconst_iterator_test(i, ++j);     | ||||
|   } | ||||
|  | ||||
|   // Test reverse_iterator_generator again, with traits fully deducible on all platforms | ||||
|   { | ||||
|     std::deque<dummyT> reversed_container; | ||||
|     std::reverse_copy(array, array + N, std::back_inserter(reversed_container)); | ||||
|     const std::deque<dummyT>::iterator reversed = reversed_container.begin(); | ||||
|  | ||||
|  | ||||
|     typedef boost::reverse_iterator_generator< | ||||
|         std::deque<dummyT>::iterator>::type reverse_iterator; | ||||
|     typedef boost::reverse_iterator_generator< | ||||
|         std::deque<dummyT>::const_iterator, const dummyT>::type const_reverse_iterator; | ||||
|  | ||||
|     // MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation | ||||
|     // (e.g. "reversed + N") is used in the constructor below. | ||||
|     const std::deque<dummyT>::iterator finish = reversed_container.end(); | ||||
|     reverse_iterator i(finish); | ||||
|      | ||||
|     boost::random_access_iterator_test(i, N, array); | ||||
|     boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array); | ||||
|  | ||||
|     const_reverse_iterator j = reverse_iterator(finish); | ||||
|     boost::random_access_iterator_test(j, N, array); | ||||
|  | ||||
|     const std::deque<dummyT>::const_iterator const_reversed = reversed; | ||||
|     boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array); | ||||
|      | ||||
|     // Many compilers' builtin deque iterators don't interoperate well, though | ||||
|     // STLport fixes that problem. | ||||
| #if defined(__SGI_STL_PORT) || !defined(__GNUC__) && !defined(__BORLANDC__) && !defined(BOOST_MSVC) | ||||
|     boost::const_nonconst_iterator_test(i, ++j); | ||||
| #endif | ||||
|   } | ||||
|    | ||||
|   // Test integer_range's iterators | ||||
|   { | ||||
|     int int_array[] = { 0, 1, 2, 3, 4, 5 }; | ||||
| @@ -170,7 +232,106 @@ main() | ||||
|     boost::random_access_iterator_test(r.begin(), r.size(), int_array); | ||||
|   } | ||||
|  | ||||
|   std::cout << "test successful " << std::endl; | ||||
|   // Test filter iterator | ||||
|   { | ||||
|     // Using typedefs for filter_gen::type confused Borland terribly. | ||||
|     typedef boost::detail::non_bidirectional_category<dummyT*>::type category; | ||||
|      | ||||
|     typedef boost::filter_iterator_generator<one_or_four, dummyT* | ||||
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|         , dummyT | ||||
| #endif | ||||
|         >::type filter_iter; | ||||
|  | ||||
| #if defined(__BORLANDC__) | ||||
|     // Borland is choking on accessing the policies_type explicitly | ||||
|     // from the filter_iter.  | ||||
|     boost::forward_iterator_test(make_filter_iterator(array, array+N,  | ||||
| 						      one_or_four()), | ||||
| 				 dummyT(1), dummyT(4)); | ||||
| #else | ||||
|     filter_iter i(array, filter_iter::policies_type(one_or_four(), array + N)); | ||||
|     boost::forward_iterator_test(i, dummyT(1), dummyT(4)); | ||||
| #endif | ||||
|  | ||||
| #if !defined(__BORLANDC__) | ||||
|     //  | ||||
|     enum { is_forward = boost::is_same< | ||||
|            filter_iter::iterator_category, | ||||
|            std::forward_iterator_tag>::value }; | ||||
|     BOOST_STATIC_ASSERT(is_forward); | ||||
| #endif | ||||
|  | ||||
|     // On compilers not supporting partial specialization, we can do more type | ||||
|     // deduction with deque iterators than with pointers... unless the library | ||||
|     // is broken ;-( | ||||
| #if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT) | ||||
|     std::deque<dummyT> array2; | ||||
|     std::copy(array+0, array+N, std::back_inserter(array2)); | ||||
|     boost::forward_iterator_test( | ||||
|         boost::make_filter_iterator(array2.begin(), array2.end(), one_or_four()), | ||||
|         dummyT(1), dummyT(4)); | ||||
|  | ||||
|     boost::forward_iterator_test( | ||||
|         boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()), | ||||
|         dummyT(1), dummyT(4)); | ||||
| #endif | ||||
|  | ||||
| #if !defined(BOOST_MSVC) // This just freaks MSVC out completely | ||||
|     boost::forward_iterator_test( | ||||
|         boost::make_filter_iterator<one_or_four>( | ||||
|             boost::make_reverse_iterator(array2.end()), | ||||
|             boost::make_reverse_iterator(array2.begin()) | ||||
|             ), | ||||
|         dummyT(4), dummyT(1)); | ||||
| #endif | ||||
|      | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|     boost::forward_iterator_test( | ||||
|         boost::make_filter_iterator(array+0, array+N, one_or_four()), | ||||
|         dummyT(1), dummyT(4)); | ||||
|  | ||||
|     boost::forward_iterator_test( | ||||
|         boost::make_filter_iterator<one_or_four>(array, array + N), | ||||
|         dummyT(1), dummyT(4)); | ||||
|  | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   // check operator-> with a forward iterator | ||||
|   { | ||||
|     boost::forward_iterator_archetype<dummyT> forward_iter; | ||||
| #if defined(__BORLANDC__) | ||||
|     typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>, | ||||
|       boost::default_iterator_policies, | ||||
|       dummyT, const dummyT&, const dummyT*,  | ||||
|       std::forward_iterator_tag, std::ptrdiff_t> adaptor_type; | ||||
| #else | ||||
|     typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>, | ||||
|       boost::default_iterator_policies, | ||||
|       boost::value_type_is<dummyT>, | ||||
|       boost::reference_is<const dummyT&>, | ||||
|       boost::pointer_is<const dummyT*>, | ||||
|       boost::iterator_category_is<std::forward_iterator_tag>, | ||||
|       boost::difference_type_is<std::ptrdiff_t> > adaptor_type; | ||||
| #endif | ||||
|     adaptor_type i(forward_iter); | ||||
|     int zero = 0; | ||||
|     if (zero) // don't do this, just make sure it compiles | ||||
|       assert((*i).m_x == i->foo());       | ||||
|   } | ||||
|   // check operator-> with an input iterator | ||||
|   { | ||||
|     boost::input_iterator_archetype<dummyT> input_iter; | ||||
|     typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>, | ||||
|       boost::default_iterator_policies, | ||||
|       dummyT, const dummyT&, const dummyT*,  | ||||
|       std::input_iterator_tag, std::ptrdiff_t> adaptor_type; | ||||
|     adaptor_type i(input_iter); | ||||
|     int zero = 0; | ||||
|     if (zero) // don't do this, just make sure it compiles | ||||
|       assert((*i).m_x == i->foo());       | ||||
|   } | ||||
|   std::cout << "test successful " << std::endl; | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										210
									
								
								iterator_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								iterator_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| //  (C) Copyright David Abrahams 2001. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  04 Mar 2001 Patches for Intel C++ (Dave Abrahams) | ||||
| //  19 Feb 2001 Take advantage of improved iterator_traits to do more tests | ||||
| //              on MSVC. Reordered some #ifdefs for coherency. | ||||
| //              (David Abrahams) | ||||
| //  13 Feb 2001 Test new VC6 workarounds (David Abrahams) | ||||
| //  11 Feb 2001 Final fixes for Borland (David Abrahams) | ||||
| //  11 Feb 2001 Some fixes for Borland get it closer on that compiler | ||||
| //              (David Abrahams) | ||||
| //  07 Feb 2001 More comprehensive testing; factored out static tests for | ||||
| //              better reuse (David Abrahams) | ||||
| //  21 Jan 2001 Quick fix to my_iterator, which wasn't returning a | ||||
| //              reference type from operator* (David Abrahams) | ||||
| //  19 Jan 2001 Initial version with iterator operators (David Abrahams) | ||||
|  | ||||
| #include <boost/detail/iterator.hpp> | ||||
| #include <boost/type_traits.hpp> | ||||
| #include <boost/operators.hpp> | ||||
| #include <boost/static_assert.hpp> | ||||
| #include <iterator> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| #include <cassert> | ||||
| #include <iostream> | ||||
|  | ||||
| // An iterator for which we can get traits. | ||||
| struct my_iterator1 | ||||
|     : boost::forward_iterator_helper<my_iterator1, char, long, const char*, const char&> | ||||
| { | ||||
|     my_iterator1(const char* p) : m_p(p) {} | ||||
|      | ||||
|     bool operator==(const my_iterator1& rhs) const | ||||
|         { return this->m_p == rhs.m_p; } | ||||
|  | ||||
|     my_iterator1& operator++() { ++this->m_p; return *this; } | ||||
|     const char& operator*() { return *m_p; } | ||||
|  private: | ||||
|     const char* m_p; | ||||
| }; | ||||
|  | ||||
| // Used to prove that we don't require std::iterator<> in the hierarchy under | ||||
| // MSVC6, and that we can compute all the traits for a standard-conforming UDT | ||||
| // iterator. | ||||
| struct my_iterator2 | ||||
|     : boost::equality_comparable<my_iterator2 | ||||
|     , boost::incrementable<my_iterator2 | ||||
|     , boost::dereferenceable<my_iterator2,const char*> > > | ||||
| { | ||||
|     typedef char value_type; | ||||
|     typedef long difference_type; | ||||
|     typedef const char* pointer; | ||||
|     typedef const char& reference; | ||||
|     typedef std::forward_iterator_tag iterator_category; | ||||
|      | ||||
|     my_iterator2(const char* p) : m_p(p) {} | ||||
|      | ||||
|     bool operator==(const my_iterator2& rhs) const | ||||
|         { return this->m_p == rhs.m_p; } | ||||
|  | ||||
|     my_iterator2& operator++() { ++this->m_p; return *this; } | ||||
|     const char& operator*() { return *m_p; } | ||||
|  private: | ||||
|     const char* m_p; | ||||
| }; | ||||
|  | ||||
| // Used to prove that we're not overly confused by the existence of | ||||
| // std::iterator<> in the hierarchy under MSVC6 - we should find that | ||||
| // boost::detail::iterator_traits<my_iterator3>::difference_type is int. | ||||
| struct my_iterator3 : my_iterator1 | ||||
| { | ||||
|     typedef int difference_type; | ||||
|     my_iterator3(const char* p) : my_iterator1(p) {} | ||||
| }; | ||||
|  | ||||
| template <class Iterator, | ||||
|     class value_type, class difference_type, class pointer, class reference, class category> | ||||
| struct non_portable_tests | ||||
| { | ||||
|     // Unfortunately, the VC6 standard library doesn't supply these :( | ||||
|     BOOST_STATIC_ASSERT(( | ||||
|         boost::is_same< | ||||
|         typename boost::detail::iterator_traits<Iterator>::pointer, | ||||
|         pointer | ||||
|         >::value)); | ||||
|      | ||||
|     BOOST_STATIC_ASSERT(( | ||||
|         boost::is_same< | ||||
|         typename boost::detail::iterator_traits<Iterator>::reference, | ||||
|         reference | ||||
|         >::value)); | ||||
| }; | ||||
|  | ||||
| template <class Iterator, | ||||
|     class value_type, class difference_type, class pointer, class reference, class category> | ||||
| struct portable_tests | ||||
| { | ||||
|     BOOST_STATIC_ASSERT(( | ||||
|         boost::is_same< | ||||
|         typename boost::detail::iterator_traits<Iterator>::difference_type, | ||||
|         difference_type | ||||
|         >::value)); | ||||
|      | ||||
|     BOOST_STATIC_ASSERT(( | ||||
|         boost::is_same< | ||||
|         typename boost::detail::iterator_traits<Iterator>::iterator_category, | ||||
|         category | ||||
|         >::value)); | ||||
| }; | ||||
|  | ||||
| // Test iterator_traits | ||||
| template <class Iterator, | ||||
|     class value_type, class difference_type, class pointer, class reference, class category> | ||||
| struct input_iterator_test | ||||
|     : portable_tests<Iterator,value_type,difference_type,pointer,reference,category> | ||||
| { | ||||
|     BOOST_STATIC_ASSERT(( | ||||
|         boost::is_same< | ||||
|         typename boost::detail::iterator_traits<Iterator>::value_type, | ||||
|         value_type | ||||
|         >::value)); | ||||
| }; | ||||
|  | ||||
| template <class Iterator, | ||||
|     class value_type, class difference_type, class pointer, class reference, class category> | ||||
| struct non_pointer_test | ||||
|     : input_iterator_test<Iterator,value_type,difference_type,pointer,reference,category> | ||||
|       , non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category> | ||||
| { | ||||
| }; | ||||
|  | ||||
| template <class Iterator, | ||||
|     class value_type, class difference_type, class pointer, class reference, class category> | ||||
| struct maybe_pointer_test | ||||
|     : portable_tests<Iterator,value_type,difference_type,pointer,reference,category> | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|       , non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category> | ||||
| #endif | ||||
| { | ||||
| }; | ||||
|  | ||||
| input_iterator_test<std::istream_iterator<int>, int, std::ptrdiff_t, int*, int&, std::input_iterator_tag> | ||||
|         istream_iterator_test; | ||||
|  | ||||
| //  | ||||
| #if defined(__BORLANDC__) && !defined(__SGI_STL_PORT) | ||||
| typedef ::std::char_traits<char>::off_type distance; | ||||
| non_pointer_test<std::ostream_iterator<int>,int, | ||||
|     distance,int*,int&,std::output_iterator_tag> ostream_iterator_test; | ||||
| #elif defined(BOOST_MSVC_STD_ITERATOR) | ||||
| non_pointer_test<std::ostream_iterator<int>, | ||||
|     int, void, void, void, std::output_iterator_tag> | ||||
|         ostream_iterator_test; | ||||
| #else | ||||
| non_pointer_test<std::ostream_iterator<int>, | ||||
|     void, void, void, void, std::output_iterator_tag> | ||||
|         ostream_iterator_test; | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef __KCC | ||||
|   typedef long std_list_diff_type; | ||||
| #else | ||||
|   typedef std::ptrdiff_t std_list_diff_type; | ||||
| #endif | ||||
| non_pointer_test<std::list<int>::iterator, int, std_list_diff_type, int*, int&, std::bidirectional_iterator_tag> | ||||
|         list_iterator_test; | ||||
|  | ||||
| maybe_pointer_test<std::vector<int>::iterator, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag> | ||||
|         vector_iterator_test; | ||||
|  | ||||
| maybe_pointer_test<int*, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag> | ||||
|         int_pointer_test; | ||||
|  | ||||
| non_pointer_test<my_iterator1, char, long, const char*, const char&, std::forward_iterator_tag> | ||||
|        my_iterator1_test; | ||||
|                      | ||||
| non_pointer_test<my_iterator2, char, long, const char*, const char&, std::forward_iterator_tag> | ||||
|        my_iterator2_test; | ||||
|                      | ||||
| non_pointer_test<my_iterator3, char, int, const char*, const char&, std::forward_iterator_tag> | ||||
|        my_iterator3_test; | ||||
|                      | ||||
| int main() | ||||
| { | ||||
|     char chars[100]; | ||||
|     int ints[100]; | ||||
|      | ||||
|     for (std::ptrdiff_t length = 3; length < 100; length += length / 3) | ||||
|     { | ||||
|         std::list<int> l(length); | ||||
|         assert(boost::detail::distance(l.begin(), l.end()) == length); | ||||
|          | ||||
|         std::vector<int> v(length); | ||||
|         assert(boost::detail::distance(v.begin(), v.end()) == length); | ||||
|  | ||||
|         assert(boost::detail::distance(&ints[0], ints + length) == length); | ||||
|         assert(boost::detail::distance(my_iterator1(chars), my_iterator1(chars + length)) == length); | ||||
|         assert(boost::detail::distance(my_iterator2(chars), my_iterator2(chars + length)) == length); | ||||
|         assert(boost::detail::distance(my_iterator3(chars), my_iterator3(chars + length)) == length); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| @@ -9,16 +9,25 @@ | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  29 May 01 Factored implementation, added comparison tests, use Test Tools | ||||
| //            library (Daryle Walker) | ||||
| //  12 Dec 99 Initial version with iterator operators (Jeremy Siek) | ||||
|  | ||||
| #include <string> | ||||
| #include <iostream> | ||||
| using namespace std; | ||||
| #define  BOOST_INCLUDE_MAIN | ||||
| #include <boost/test/test_tools.hpp>  // for main | ||||
|  | ||||
| #include <boost/operators.hpp> | ||||
| using namespace boost; | ||||
| #include <boost/config.hpp>     // for BOOST_STATIC_CONSTANT | ||||
| #include <boost/cstdlib.hpp>    // for boost::exit_success | ||||
| #include <boost/operators.hpp>  // for boost::random_access_iterator_helper | ||||
|  | ||||
| #include <cstddef>    // for std::ptrdiff_t, std::size_t | ||||
| #include <cstring>    // for std::strcmp | ||||
| #include <iostream>   // for std::cout (std::endl, ends, and flush indirectly) | ||||
| #include <string>     // for std::string | ||||
| #include <strstream>  // for std::ostrstream | ||||
|  | ||||
|  | ||||
| // Iterator test class | ||||
| template <class T, class R, class P> | ||||
| struct test_iter | ||||
|   : public boost::random_access_iterator_helper< | ||||
| @@ -29,7 +38,7 @@ struct test_iter | ||||
|   typedef std::ptrdiff_t Distance; | ||||
|  | ||||
| public: | ||||
|   test_iter(T* i) : _i(i) { } | ||||
|   explicit test_iter(T* i =0) : _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; } | ||||
| @@ -43,127 +52,280 @@ public: | ||||
|     return x._i - y._i;  | ||||
|   } | ||||
| protected: | ||||
|   T* _i; | ||||
|   P _i; | ||||
| }; | ||||
|  | ||||
|  | ||||
| int | ||||
| main() | ||||
| // Iterator operator testing classes | ||||
| class test_opr_base | ||||
| { | ||||
|   string array[] = { "apple", "orange", "pear", "peach", "grape", "plum"  }; | ||||
|   { | ||||
|     test_iter<string,string&,string*> i = array,  | ||||
|       ie = array + sizeof(array)/sizeof(string); | ||||
| protected: | ||||
|     // Test data and types | ||||
|     BOOST_STATIC_CONSTANT( std::size_t, fruit_length = 6u ); | ||||
|     BOOST_STATIC_CONSTANT( std::size_t, scratch_length = 40u ); | ||||
|  | ||||
|     // Tests for all of the operators added by random_access_iterator_helper | ||||
|     typedef std::string  fruit_array_type[ fruit_length ]; | ||||
|     typedef char         scratch_array_type[ scratch_length ]; | ||||
|  | ||||
|     // test i++ | ||||
|     while (i != ie) | ||||
|       cout << *i++ << " "; | ||||
|     cout << endl; | ||||
|     i = array; | ||||
|     static  fruit_array_type    fruit; | ||||
|     static  scratch_array_type  scratch; | ||||
|  | ||||
|     // test i-- | ||||
|     while (ie != i) { | ||||
|       ie--; | ||||
|       cout << *ie << " "; | ||||
|     } | ||||
|     cout << endl; | ||||
|     ie = array + sizeof(array)/sizeof(string); | ||||
| };  // test_opr_base | ||||
|  | ||||
|     // test i->m | ||||
|     while (i != ie) { | ||||
|       cout << i->size() << " "; | ||||
|       ++i; | ||||
|     } | ||||
|     cout << endl; | ||||
|     i = array; | ||||
| template <typename T, typename R = T&, typename P = T*> | ||||
| class test_opr | ||||
|     : public test_opr_base | ||||
| { | ||||
|     typedef test_opr<T, R, P>  self_type; | ||||
|  | ||||
|     // test i + n | ||||
|     while (i < ie) { | ||||
|       cout << *i << " "; | ||||
|       i = i + 2; | ||||
|     } | ||||
|     cout << endl; | ||||
|     i = array; | ||||
| public: | ||||
|     // Types | ||||
|     typedef T  value_type; | ||||
|     typedef R  reference; | ||||
|     typedef P  pointer; | ||||
|  | ||||
|     // test n + i | ||||
|     while (i < ie) { | ||||
|       cout << *i << " "; | ||||
|       i = ptrdiff_t(2) + i; | ||||
|     } | ||||
|     cout << endl; | ||||
|     i = array; | ||||
|     typedef test_iter<T, R, P>  iter_type; | ||||
|  | ||||
|     // test i - n | ||||
|     while (ie > i) { | ||||
|       ie = ie - 2; | ||||
|       cout << *ie << " "; | ||||
|     } | ||||
|     cout << endl; | ||||
|     ie = array + sizeof(array)/sizeof(string); | ||||
|     // Test controller | ||||
|     static  void  master_test( char const name[] ); | ||||
|  | ||||
|     // 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); | ||||
| private: | ||||
|     // Test data | ||||
|     static  iter_type const  fruit_begin, fruit_end; | ||||
|  | ||||
|     // Tests for all of the operators added by random_access_iterator_helper | ||||
|     // Test parts | ||||
|     static  void  post_increment_test(); | ||||
|     static  void  post_decrement_test(); | ||||
|     static  void  indirect_referral_test(); | ||||
|     static  void  offset_addition_test(); | ||||
|     static  void  reverse_offset_addition_test(); | ||||
|     static  void  offset_subtraction_test(); | ||||
|     static  void  comparison_test(); | ||||
|     static  void  indexing_test(); | ||||
|  | ||||
|     // test i++ | ||||
|     while (i != ie) | ||||
|       cout << *i++ << " "; | ||||
|     cout << endl; | ||||
|     i = array; | ||||
| };  // test_opr | ||||
|  | ||||
|     // 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; | ||||
| // Class-static data definitions | ||||
| test_opr_base::fruit_array_type | ||||
|  test_opr_base::fruit = { "apple", "orange", "pear", "peach", "grape", "plum" }; | ||||
|  | ||||
|     // test i + n | ||||
|     while (i < ie) { | ||||
|       cout << *i << " "; | ||||
|       i = i + 2; | ||||
|     } | ||||
|     cout << endl; | ||||
|     i = array; | ||||
| test_opr_base::scratch_array_type | ||||
|  test_opr_base::scratch = ""; | ||||
|  | ||||
|     // test n + i | ||||
|     while (i < ie) { | ||||
|       cout << *i << " "; | ||||
|       i = ptrdiff_t(2) + i; | ||||
|     } | ||||
|     cout << endl; | ||||
|     i = array; | ||||
| template <typename T, typename R, typename P> | ||||
| typename test_opr<T, R, P>::iter_type const | ||||
|  test_opr<T, R, P>::fruit_begin( fruit ); | ||||
|  | ||||
|     // test i - n | ||||
|     while (ie > i) { | ||||
|       ie = ie - 2; | ||||
|       cout << *ie << " "; | ||||
|     } | ||||
|     cout << endl; | ||||
|     ie = array + sizeof(array)/sizeof(string); | ||||
| template <typename T, typename R, typename P> | ||||
| typename test_opr<T, R, P>::iter_type const | ||||
|  test_opr<T, R, P>::fruit_end( fruit + fruit_length ); | ||||
|  | ||||
|     // test i[n] | ||||
|     for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j) | ||||
|       cout << i[j] << " "; | ||||
|     cout << endl; | ||||
|   } | ||||
|   return 0; | ||||
|  | ||||
| // Main testing function | ||||
| int | ||||
| test_main( int , char * [] ) | ||||
| { | ||||
|     using std::string; | ||||
|  | ||||
|     typedef test_opr<string, string &, string *>              test1_type; | ||||
|     typedef test_opr<string, string const &, string const *>  test2_type; | ||||
|  | ||||
|     test1_type::master_test( "non-const string" ); | ||||
|     test2_type::master_test( "const string" ); | ||||
|  | ||||
|     return boost::exit_success; | ||||
| } | ||||
|  | ||||
| // Tests for all of the operators added by random_access_iterator_helper | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::master_test | ||||
| ( | ||||
|     char const  name[] | ||||
| ) | ||||
| { | ||||
|     std::cout << "Doing test run for " << name << '.' << std::endl; | ||||
|  | ||||
|     post_increment_test(); | ||||
|     post_decrement_test(); | ||||
|     indirect_referral_test(); | ||||
|     offset_addition_test(); | ||||
|     reverse_offset_addition_test(); | ||||
|     offset_subtraction_test(); | ||||
|     comparison_test(); | ||||
|     indexing_test(); | ||||
| } | ||||
|  | ||||
| // Test post-increment | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::post_increment_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing post-increment test." << std::endl; | ||||
|  | ||||
|     std::ostrstream  oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_begin ; i != fruit_end ; ) | ||||
|     { | ||||
|         oss << *i++ << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "apple orange pear peach grape plum ") | ||||
|      == 0 ); | ||||
| } | ||||
|  | ||||
| // Test post-decrement | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::post_decrement_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing post-decrement test." << std::endl; | ||||
|  | ||||
|     std::ostrstream  oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_end ; i != fruit_begin ; ) | ||||
|     { | ||||
|         i--; | ||||
|         oss << *i << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "plum grape peach pear orange apple ") | ||||
|      == 0 ); | ||||
| } | ||||
|  | ||||
| // Test indirect structure referral | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::indirect_referral_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing indirect reference test." << std::endl; | ||||
|  | ||||
|     std::ostrstream  oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_begin ; i != fruit_end ; ++i ) | ||||
|     { | ||||
|         oss << i->size() << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "5 6 4 5 5 4 ") == 0 ); | ||||
| } | ||||
|  | ||||
| // Test offset addition | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::offset_addition_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing offset addition test." << std::endl; | ||||
|  | ||||
|     std::ptrdiff_t const  two = 2; | ||||
|     std::ostrstream       oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_begin ; i != fruit_end ; i = i + two ) | ||||
|     { | ||||
|         oss << *i << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "apple pear grape ") == 0 ); | ||||
| } | ||||
|  | ||||
| // Test offset addition, in reverse order | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::reverse_offset_addition_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing reverse offset addition test." << std::endl; | ||||
|  | ||||
|     std::ptrdiff_t const  two = 2; | ||||
|     std::ostrstream       oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_begin ; i != fruit_end ; i = two + i ) | ||||
|     { | ||||
|         oss << *i << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "apple pear grape ") == 0 ); | ||||
| } | ||||
|  | ||||
| // Test offset subtraction | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::offset_subtraction_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing offset subtraction test." << std::endl; | ||||
|  | ||||
|     std::ptrdiff_t const  two = 2; | ||||
|     std::ostrstream       oss( scratch, scratch_length ); | ||||
|     for ( iter_type i = fruit_end ; fruit_begin < i ; ) | ||||
|     { | ||||
|         i = i - two; | ||||
|         if ( (fruit_begin < i) || (fruit_begin == i) ) | ||||
|         { | ||||
|             oss << *i << ' '; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "grape pear apple ") == 0 ); | ||||
| } | ||||
|  | ||||
| // Test comparisons | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::comparison_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     using std::cout; | ||||
|     using std::ptrdiff_t; | ||||
|  | ||||
|     cout << "\tDoing comparison tests.\n\t\tPass:"; | ||||
|  | ||||
|     for ( iter_type i = fruit_begin ; i != fruit_end ; ++i ) | ||||
|     { | ||||
|         ptrdiff_t const  i_offset = i - fruit_begin; | ||||
|  | ||||
|         cout << ' ' << *i << std::flush; | ||||
|         for ( iter_type j = fruit_begin ; j != fruit_end ; ++j ) | ||||
|         { | ||||
|             ptrdiff_t const  j_offset = j - fruit_begin; | ||||
|  | ||||
|             BOOST_TEST( (i != j) == (i_offset != j_offset) ); | ||||
|             BOOST_TEST( (i > j) == (i_offset > j_offset) ); | ||||
|             BOOST_TEST( (i <= j) == (i_offset <= j_offset) ); | ||||
|             BOOST_TEST( (i >= j) == (i_offset >= j_offset) ); | ||||
|         } | ||||
|     } | ||||
|     cout << std::endl; | ||||
| } | ||||
|  | ||||
| // Test indexing | ||||
| template <typename T, typename R, typename P> | ||||
| void | ||||
| test_opr<T, R, P>::indexing_test | ||||
| ( | ||||
| ) | ||||
| { | ||||
|     std::cout << "\tDoing indexing test." << std::endl; | ||||
|  | ||||
|     std::ostrstream  oss( scratch, scratch_length ); | ||||
|     for ( std::size_t k = 0u ; k < fruit_length ; ++k ) | ||||
|     { | ||||
|         oss << fruit_begin[ k ] << ' '; | ||||
|     } | ||||
|  | ||||
|     oss << std::ends; | ||||
|     BOOST_TEST( std::strcmp(oss.str(), "apple orange pear peach grape plum ") | ||||
|      == 0 ); | ||||
| } | ||||
|   | ||||
							
								
								
									
										393
									
								
								numeric_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								numeric_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,393 @@ | ||||
| //  (C) Copyright David Abrahams 2001. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  11 Feb 2001 Fixes for Borland (David Abrahams) | ||||
| //  23 Jan 2001 Added test for wchar_t (David Abrahams) | ||||
| //  23 Jan 2001 Now statically selecting a test for signed numbers to avoid | ||||
| //              warnings with fancy compilers. Added commentary and | ||||
| //              additional dumping of traits data for tested types (David | ||||
| //              Abrahams). | ||||
| //  21 Jan 2001 Initial version (David Abrahams) | ||||
|  | ||||
| #include <boost/detail/numeric_traits.hpp> | ||||
| #include <cassert> | ||||
| #include <boost/type_traits.hpp> | ||||
| #include <boost/static_assert.hpp> | ||||
| #include <boost/cstdint.hpp> | ||||
| #include <boost/utility.hpp> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <climits> | ||||
| #include <typeinfo> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #ifndef BOOST_NO_LIMITS | ||||
| # include <limits> | ||||
| #endif | ||||
|  | ||||
| // A macro for declaring class compile-time constants. | ||||
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION | ||||
| # define DECLARE_CLASS_CONST(type, init) static const type init | ||||
| #else | ||||
| # define DECLARE_CLASS_CONST(type, init) enum { init } | ||||
| #endif | ||||
|  | ||||
| // ================================================================================= | ||||
| // template class complement_traits<Number> -- | ||||
| // | ||||
| //    statically computes the max and min for 1s and 2s-complement binary | ||||
| //    numbers. This helps on platforms without <limits> support. It also shows | ||||
| //    an example of a recursive template that works with MSVC! | ||||
| // | ||||
|  | ||||
| template <unsigned size> struct complement; // forward | ||||
|  | ||||
| // The template complement, below, does all the real work, using "poor man's | ||||
| // partial specialization". We need complement_traits_aux<> so that MSVC doesn't | ||||
| // complain about undefined min/max as we're trying to recursively define them.  | ||||
| template <class Number, unsigned size> | ||||
| struct complement_traits_aux | ||||
| { | ||||
|     DECLARE_CLASS_CONST(Number, max = complement<size>::template traits<Number>::max); | ||||
|     DECLARE_CLASS_CONST(Number, min = complement<size>::template traits<Number>::min); | ||||
| }; | ||||
|  | ||||
| template <unsigned size> | ||||
| struct complement | ||||
| { | ||||
|     template <class Number> | ||||
|     struct traits | ||||
|     { | ||||
|      private: | ||||
|         // indirection through complement_traits_aux neccessary to keep MSVC happy | ||||
|         typedef complement_traits_aux<Number, size - 1> prev; | ||||
|      public: | ||||
|         DECLARE_CLASS_CONST(Number, max = | ||||
|                             Number(Number(prev::max) << CHAR_BIT) | ||||
|                             + Number(UCHAR_MAX)); | ||||
|          | ||||
|         DECLARE_CLASS_CONST(Number, min = Number(Number(prev::min) << CHAR_BIT)); | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| // Template class complement_base<> -- defines values for min and max for | ||||
| // complement<1>, at the deepest level of recursion. Uses "poor man's partial | ||||
| // specialization" again. | ||||
| template <bool is_signed> struct complement_base; | ||||
|  | ||||
| template <> struct complement_base<false> | ||||
| { | ||||
|     template <class Number> | ||||
|     struct values | ||||
|     { | ||||
|         DECLARE_CLASS_CONST(Number, min = 0); | ||||
|         DECLARE_CLASS_CONST(Number, max = UCHAR_MAX); | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| template <> struct complement_base<true> | ||||
| { | ||||
|     template <class Number> | ||||
|     struct values | ||||
|     { | ||||
|         DECLARE_CLASS_CONST(Number, min = SCHAR_MIN); | ||||
|         DECLARE_CLASS_CONST(Number, max = SCHAR_MAX); | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| // Base specialization of complement, puts an end to the recursion. | ||||
| template <> | ||||
| struct complement<1> | ||||
| { | ||||
|     template <class Number> | ||||
|     struct traits | ||||
|     { | ||||
|         DECLARE_CLASS_CONST(bool, is_signed = boost::detail::is_signed<Number>::value); | ||||
|         DECLARE_CLASS_CONST(Number, min = | ||||
|                             complement_base<is_signed>::template values<Number>::min); | ||||
|         DECLARE_CLASS_CONST(Number, max = | ||||
|                             complement_base<is_signed>::template values<Number>::max); | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| // Now here's the "pretty" template you're intended to actually use. | ||||
| //   complement_traits<Number>::min, complement_traits<Number>::max are the | ||||
| //   minimum and maximum values of Number if Number is a built-in integer type. | ||||
| template <class Number> | ||||
| struct complement_traits | ||||
| { | ||||
|     DECLARE_CLASS_CONST(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max)); | ||||
|     DECLARE_CLASS_CONST(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min)); | ||||
| }; | ||||
|  | ||||
| // ================================================================================= | ||||
|  | ||||
| // Support for streaming various numeric types in exactly the format I want. I | ||||
| // needed this in addition to all the assertions so that I could see exactly | ||||
| // what was going on. | ||||
| // | ||||
| // Numbers go through a 2-stage conversion process (by default, though, no real | ||||
| // conversion). | ||||
| // | ||||
| template <class T> struct stream_as { | ||||
|     typedef T t1; | ||||
|     typedef T t2; | ||||
| }; | ||||
|  | ||||
| // char types first get converted to unsigned char, then to unsigned. | ||||
| template <> struct stream_as<char> { | ||||
|     typedef unsigned char t1; | ||||
|     typedef unsigned t2; | ||||
| }; | ||||
| template <> struct stream_as<unsigned char> { | ||||
|     typedef unsigned char t1; typedef unsigned t2; | ||||
| }; | ||||
| template <> struct stream_as<signed char>  { | ||||
|     typedef unsigned char t1; typedef unsigned t2; | ||||
| }; | ||||
|  | ||||
| #if defined(BOOST_MSVC) // No intmax streaming built-in | ||||
|  | ||||
| // On this platform, __int64 and __uint64 get streamed as strings | ||||
| template <> struct stream_as<boost::uintmax_t> { | ||||
|     typedef std::string t1; | ||||
|     typedef std::string t2; | ||||
| }; | ||||
|  | ||||
| template <> struct stream_as<boost::intmax_t>  { | ||||
|     typedef std::string t1; | ||||
|     typedef std::string t2; | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| // Standard promotion process for streaming | ||||
| template <class T> struct promote | ||||
| { | ||||
|     static typename stream_as<T>::t1 from(T x) { | ||||
|         typedef typename stream_as<T>::t1 t1; | ||||
|         return t1(x); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| #if defined(BOOST_MSVC) // No intmax streaming built-in | ||||
|  | ||||
| // On this platform, stream them as long/unsigned long if they fit. | ||||
| // Otherwise, write a string. | ||||
| template <> struct promote<boost::uintmax_t> { | ||||
|     std::string static from(const boost::uintmax_t x) { | ||||
|         if (x > ULONG_MAX) | ||||
|             return std::string("large unsigned value"); | ||||
|         else | ||||
|             return boost::lexical_cast<std::string>((unsigned long)x); | ||||
|     } | ||||
| }; | ||||
| template <> struct promote<boost::intmax_t> { | ||||
|     std::string static from(const boost::intmax_t x) { | ||||
|         if (x > boost::intmax_t(ULONG_MAX)) | ||||
|             return std::string("large positive signed value"); | ||||
|         else if (x >= 0) | ||||
|             return boost::lexical_cast<std::string>((unsigned long)x); | ||||
|          | ||||
|         if (x < boost::intmax_t(LONG_MIN)) | ||||
|             return std::string("large negative signed value"); | ||||
|         else | ||||
|             return boost::lexical_cast<std::string>((long)x); | ||||
|     } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| // This is the function which converts types to the form I want to stream them in. | ||||
| template <class T> | ||||
| typename stream_as<T>::t2 stream_number(T x) | ||||
| { | ||||
|     return promote<T>::from(x); | ||||
| } | ||||
| // ================================================================================= | ||||
|  | ||||
| // | ||||
| // Tests for built-in signed and unsigned types | ||||
| // | ||||
|  | ||||
| // Tag types for selecting tests | ||||
| struct unsigned_tag {}; | ||||
| struct signed_tag {}; | ||||
|  | ||||
| // Tests for unsigned numbers. The extra default Number parameter works around | ||||
| // an MSVC bug. | ||||
| template <class Number> | ||||
| void test_aux(unsigned_tag, Number* = 0) | ||||
| { | ||||
|     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type; | ||||
|     BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value); | ||||
|     BOOST_STATIC_ASSERT( | ||||
|         (sizeof(Number) < sizeof(boost::intmax_t)) | ||||
|         | (boost::is_same<difference_type, boost::intmax_t>::value)); | ||||
|  | ||||
|     // Force casting to Number here to work around the fact that it's an enum on MSVC | ||||
|     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0)); | ||||
|     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) == Number(0)); | ||||
|      | ||||
|     const Number max = complement_traits<Number>::max; | ||||
|     const Number min = complement_traits<Number>::min; | ||||
|      | ||||
|     const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t)) | ||||
|         ? max | ||||
|         : max / 2 - 1; | ||||
|  | ||||
|     std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = " | ||||
|               << stream_number(max) << "..." << std::flush; | ||||
|     std::cout << "difference_type = " << typeid(difference_type).name() << "..." | ||||
|               << std::flush; | ||||
|      | ||||
|     difference_type d1 = boost::detail::numeric_distance(Number(0), test_max); | ||||
|     difference_type d2 = boost::detail::numeric_distance(test_max, Number(0)); | ||||
|      | ||||
|     std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; " | ||||
|               << std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush; | ||||
|  | ||||
|     assert(d1 == difference_type(test_max)); | ||||
|     assert(d2 == -difference_type(test_max)); | ||||
| } | ||||
|  | ||||
| // Tests for signed numbers. The extra default Number parameter works around an | ||||
| // MSVC bug. | ||||
| struct out_of_range_tag {}; | ||||
| struct in_range_tag {}; | ||||
|  | ||||
| // This test morsel gets executed for numbers whose difference will always be | ||||
| // representable in intmax_t | ||||
| template <class Number> | ||||
| void signed_test(in_range_tag, Number* = 0) | ||||
| { | ||||
|     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value); | ||||
|     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type; | ||||
|     const Number max = complement_traits<Number>::max; | ||||
|     const Number min = complement_traits<Number>::min; | ||||
|      | ||||
|     difference_type d1 = boost::detail::numeric_distance(min, max); | ||||
|     difference_type d2 = boost::detail::numeric_distance(max, min); | ||||
|  | ||||
|     std::cout << stream_number(min) << "->" << stream_number(max) << "=="; | ||||
|     std::cout << std::dec << stream_number(d1) << "; "; | ||||
|     std::cout << std::hex << stream_number(max) << "->" << stream_number(min) | ||||
|               << "==" << std::dec << stream_number(d2) << "..." << std::flush; | ||||
|     assert(d1 == difference_type(max) - difference_type(min)); | ||||
|     assert(d2 == difference_type(min) - difference_type(max)); | ||||
| } | ||||
|  | ||||
| // This test morsel gets executed for numbers whose difference may exceed the | ||||
| // capacity of intmax_t. | ||||
| template <class Number> | ||||
| void signed_test(out_of_range_tag, Number* = 0) | ||||
| { | ||||
|     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value); | ||||
|     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type; | ||||
|     const Number max = complement_traits<Number>::max; | ||||
|     const Number min = complement_traits<Number>::min; | ||||
|  | ||||
|     difference_type min_distance = complement_traits<difference_type>::min; | ||||
|     difference_type max_distance = complement_traits<difference_type>::max; | ||||
|  | ||||
|     const Number n1 = Number(min + max_distance); | ||||
|     const Number n2 = Number(max + min_distance); | ||||
|     difference_type d1 = boost::detail::numeric_distance(min, n1); | ||||
|     difference_type d2 = boost::detail::numeric_distance(max, n2); | ||||
|  | ||||
|     std::cout << stream_number(min) << "->" << stream_number(n1) << "=="; | ||||
|     std::cout << std::dec << stream_number(d1) << "; "; | ||||
|     std::cout << std::hex << stream_number(max) << "->" << stream_number(n2) | ||||
|               << "==" << std::dec << stream_number(d2) << "..." << std::flush; | ||||
|     assert(d1 == max_distance); | ||||
|     assert(d2 == min_distance); | ||||
| } | ||||
|  | ||||
| template <class Number> | ||||
| void test_aux(signed_tag, Number* = 0) | ||||
| { | ||||
|     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type; | ||||
|     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value); | ||||
|     BOOST_STATIC_ASSERT( | ||||
|         (sizeof(Number) < sizeof(boost::intmax_t)) | ||||
|         | (boost::is_same<difference_type, Number>::value)); | ||||
|  | ||||
|     // Force casting to Number here to work around the fact that it's an enum on MSVC | ||||
|     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0)); | ||||
|     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0)); | ||||
|      | ||||
|     const Number max = complement_traits<Number>::max; | ||||
|     const Number min = complement_traits<Number>::min; | ||||
|      | ||||
|     std::cout << std::hex << "min = " << stream_number(min) << ", max = " | ||||
|               << stream_number(max) << "..." << std::flush; | ||||
|     std::cout << "difference_type = " << typeid(difference_type).name() << "..." | ||||
|               << std::flush; | ||||
|  | ||||
|     typedef typename boost::detail::if_true< | ||||
|                           (sizeof(Number) < sizeof(boost::intmax_t))> | ||||
|                         ::template then< | ||||
|                           in_range_tag, | ||||
|                           out_of_range_tag | ||||
|                         >::type | ||||
|         range_tag; | ||||
|     signed_test<Number>(range_tag()); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Test for all numbers. The extra default Number parameter works around an MSVC | ||||
| // bug. | ||||
| template <class Number> | ||||
| void test(Number* = 0) | ||||
| { | ||||
|     std::cout << "testing " << typeid(Number).name() << ":\n" | ||||
| #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | ||||
|               << "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n") | ||||
|               << "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n") | ||||
|               << "digits: " << std::numeric_limits<Number>::digits << "\n" | ||||
| #endif | ||||
|               << "..." << std::flush; | ||||
|  | ||||
|     // factoring out difference_type for the assert below confused Borland :( | ||||
|     typedef boost::detail::is_signed< | ||||
| #ifndef BOOST_MSVC | ||||
|         typename | ||||
| #endif | ||||
|         boost::detail::numeric_traits<Number>::difference_type | ||||
|         > is_signed; | ||||
|     BOOST_STATIC_ASSERT(is_signed::value); | ||||
|  | ||||
|     typedef typename boost::detail::if_true< | ||||
|         boost::detail::is_signed<Number>::value | ||||
|         >::template then<signed_tag, unsigned_tag>::type signedness; | ||||
|      | ||||
|     test_aux<Number>(signedness()); | ||||
|     std::cout << "passed" << std::endl; | ||||
| } | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     test<char>(); | ||||
|     test<unsigned char>(); | ||||
|     test<signed char>(); | ||||
|     test<wchar_t>(); | ||||
|     test<short>(); | ||||
|     test<unsigned short>(); | ||||
|     test<int>(); | ||||
|     test<unsigned int>(); | ||||
|     test<long>(); | ||||
|     test<unsigned long>(); | ||||
| #if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX) | ||||
|     test<long long>(); | ||||
|     test<unsigned long long>(); | ||||
| #elif defined(BOOST_MSVC) | ||||
|     // The problem of not having compile-time static class constants other than | ||||
|     // enums prevents this from working, since values get truncated. | ||||
|     // test<boost::uintmax_t>(); | ||||
|     // test<boost::intmax_t>(); | ||||
| #endif | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										1513
									
								
								operators.htm
									
									
									
									
									
								
							
							
						
						
									
										1513
									
								
								operators.htm
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -8,18 +8,26 @@ | ||||
| //  See http://www.boost.org for most recent version including documentation. | ||||
|  | ||||
| //  Revision History | ||||
| //  20 May 01 Output progress messages.  Added tests for new operator | ||||
| //            templates.  Updated random number generator.  Changed tests to | ||||
| //            use Boost Test Tools library.  (Daryle Walker) | ||||
| //  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) | ||||
| //            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> | ||||
| #define BOOST_INCLUDE_MAIN | ||||
|  | ||||
| #include <boost/config.hpp>                      // for BOOST_MSVC | ||||
| #include <boost/cstdlib.hpp>                     // for boost::exit_success | ||||
| #include <boost/operators.hpp>                   // for the tested items | ||||
| #include <boost/random/linear_congruential.hpp>  // for boost::minstd_rand | ||||
| #include <boost/test/test_tools.hpp>             // for main | ||||
|  | ||||
| #include <iostream>  // for std::cout (std::endl indirectly) | ||||
|  | ||||
|  | ||||
| namespace | ||||
| @@ -28,14 +36,18 @@ namespace | ||||
|     int true_value(int x) { return x; } | ||||
|     long true_value(long x) { return x; } | ||||
|     signed char true_value(signed char x) { return x; } | ||||
|     short true_value(short 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; } | ||||
|     unsigned short true_value(unsigned short x) { return x; } | ||||
|  | ||||
|     // The use of operators<> here tended to obscure interactions with certain | ||||
|     // compiler bugs | ||||
|     // The use of operators<> here tended to obscure | ||||
|     // interactions with certain compiler bugs | ||||
|     template <class T> | ||||
|     class Wrapped1 : boost::operators<Wrapped1<T> > | ||||
|     class Wrapped1 | ||||
|         : boost::operators<Wrapped1<T> > | ||||
|         , boost::shiftable<Wrapped1<T> > | ||||
|     { | ||||
|     public: | ||||
|         explicit Wrapped1( T v = T() ) : _value(v) {} | ||||
| @@ -60,6 +72,10 @@ namespace | ||||
|           { _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; } | ||||
|          | ||||
| @@ -70,9 +86,11 @@ namespace | ||||
|     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> | ||||
|     class Wrapped2 | ||||
|         : boost::operators<Wrapped2<T, U> > | ||||
|         , boost::operators2<Wrapped2<T, U>, U> | ||||
|         , boost::shiftable1<Wrapped2<T, U> | ||||
|         , boost::shiftable2<Wrapped2<T, U>, U > > | ||||
|     { | ||||
|     public: | ||||
|         explicit Wrapped2( T v = T() ) : _value(v) {} | ||||
| @@ -97,6 +115,10 @@ namespace | ||||
|           { _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; } | ||||
|           | ||||
| @@ -111,6 +133,8 @@ namespace | ||||
|         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; | ||||
| @@ -118,203 +142,268 @@ namespace | ||||
|     template <class T, class U> | ||||
|     T true_value(Wrapped2<T,U> x) { return x.value(); } | ||||
|      | ||||
|     template <class T> | ||||
|     class Wrapped3 | ||||
|         : boost::equivalent<Wrapped3<T> > | ||||
|         , boost::partially_ordered<Wrapped3<T> > | ||||
|         , boost::equality_comparable<Wrapped3<T> > | ||||
|     { | ||||
|     public: | ||||
|         explicit Wrapped3( T v = T() ) : _value(v) {} | ||||
|         T value() const { return _value; } | ||||
|  | ||||
|         bool operator<(const Wrapped3& x) const { return _value < x._value; } | ||||
|          | ||||
|     private: | ||||
|         T _value; | ||||
|     }; | ||||
|     template <class T> | ||||
|     T true_value(Wrapped3<T> x) { return x.value(); }     | ||||
|  | ||||
|     template <class T, class U> | ||||
|     class Wrapped4 | ||||
|         : boost::equality_comparable1<Wrapped4<T, U> | ||||
|         , boost::equivalent1<Wrapped4<T, U> | ||||
|         , boost::partially_ordered1<Wrapped4<T, U> > > > | ||||
|         , boost::partially_ordered2<Wrapped4<T, U>, U | ||||
|         , boost::equivalent2<Wrapped4<T, U>, U | ||||
|         , boost::equality_comparable2<Wrapped4<T, U>, U> > > | ||||
|     { | ||||
|     public: | ||||
|         explicit Wrapped4( T v = T() ) : _value(v) {} | ||||
|         T value() const { return _value; } | ||||
|  | ||||
|         bool operator<(const Wrapped4& x) const { return _value < x._value; } | ||||
|           | ||||
|         bool operator<(U u) const { return _value < u; } | ||||
|         bool operator>(U u) const { return _value > u; } | ||||
|  | ||||
|     private: | ||||
|         T _value; | ||||
|     }; | ||||
|     template <class T, class U> | ||||
|     T true_value(Wrapped4<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; | ||||
|  | ||||
|     typedef Wrapped3<signed char> MyChar; | ||||
|  | ||||
|     typedef Wrapped4<short, short> MyShort; | ||||
|  | ||||
|     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)); | ||||
|         BOOST_TEST( true_value(y1) == true_value(y2) ); | ||||
|         BOOST_TEST( 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)); | ||||
|         BOOST_TEST( (x1 < y1) == (x2 < y2) ); | ||||
|         BOOST_TEST( (x1 <= y1) == (x2 <= y2) ); | ||||
|         BOOST_TEST( (x1 >= y1) == (x2 >= y2) ); | ||||
|         BOOST_TEST( (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); | ||||
|         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)); | ||||
|         BOOST_TEST( (x1 == y1) == (x2 == y2) ); | ||||
|         BOOST_TEST( (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); | ||||
|         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)); | ||||
|         BOOST_TEST( (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); | ||||
|         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)); | ||||
|         BOOST_TEST( (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); | ||||
|         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); | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         BOOST_TEST( (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); | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         if ( y2 != 0 ) | ||||
|             BOOST_TEST( (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); | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         if ( y2 != 0 ) | ||||
|             BOOST_TEST( (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)); | ||||
|         BOOST_TEST( (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); | ||||
|         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)); | ||||
|         BOOST_TEST( (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); | ||||
|         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)); | ||||
|         BOOST_TEST( (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); | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         test_orable_aux( x1, y1, x2, y2 ); | ||||
|         test_orable_aux( y1, x1, y2, x2 ); | ||||
|     } | ||||
|      | ||||
|     template <class X1, class Y1, class X2, class Y2> | ||||
|     void test_left_shiftable(X1 x1, Y1 y1, X2 x2, Y2 y2) | ||||
|     { | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         BOOST_TEST( (x1 << y1).value() == (x2 << y2) ); | ||||
|     } | ||||
|      | ||||
|     template <class X1, class Y1, class X2, class Y2> | ||||
|     void test_right_shiftable(X1 x1, Y1 y1, X2 x2, Y2 y2) | ||||
|     { | ||||
|         sanity_check( x1, y1, x2, y2 ); | ||||
|         BOOST_TEST( (x1 >> y1).value() == (x2 >> y2) ); | ||||
|     } | ||||
|      | ||||
|     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); | ||||
|         sanity_check( x1, x1, x2, x2 ); | ||||
|         BOOST_TEST( (x1++).value() == x2++ ); | ||||
|         BOOST_TEST( 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); | ||||
|         sanity_check( x1, x1, x2, x2 ); | ||||
|         BOOST_TEST( (x1--).value() == x2-- ); | ||||
|         BOOST_TEST( 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); | ||||
|         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_left_shiftable( x1, y1, x2, y2 ); | ||||
|         test_right_shiftable( 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 | ||||
|         void operator()(boost::minstd_rand& randomizer) const | ||||
|         { | ||||
|             Big b1 = Big(randomizer()); | ||||
|             Big b2 = Big(randomizer()); | ||||
|             Small s = Small(randomizer()); | ||||
|             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); | ||||
|             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> > | ||||
|         : 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; } | ||||
|         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 | ||||
|  | ||||
|  | ||||
| @@ -340,20 +429,25 @@ 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 | ||||
| #define PRIVATE_EXPR_TEST(e, t)  BOOST_TEST( ((e), (t)) ) | ||||
|  | ||||
| int main() | ||||
|  | ||||
| int | ||||
| test_main( int , char * [] ) | ||||
| { | ||||
|     using std::cout; | ||||
|     using std::endl; | ||||
|  | ||||
|     // Regression test. | ||||
|     Point x; | ||||
|     x = x + Point(3, 4); | ||||
|     x = x - Point(3, 4); | ||||
|      | ||||
|     cout << "Created point, and operated on it." << endl; | ||||
|      | ||||
|     for (int n = 0; n < 10000; ++n) | ||||
|     { | ||||
|         boost::min_rand r; | ||||
|         boost::minstd_rand r; | ||||
|         tester<long, int>()(r); | ||||
|         tester<long, signed char>()(r); | ||||
|         tester<long, long>()(r); | ||||
| @@ -367,115 +461,197 @@ int main() | ||||
|         tester<unsigned int, unsigned char>()(r); | ||||
|     } | ||||
|      | ||||
|     cout << "Did random tester loop." << endl; | ||||
|  | ||||
|     MyInt i1(1); | ||||
|     MyInt i2(2); | ||||
|     MyInt i; | ||||
|  | ||||
|     assert( i1.value() == 1 ); | ||||
|     assert( i2.value() == 2 ); | ||||
|     assert( i.value() == 0 ); | ||||
|     BOOST_TEST( i1.value() == 1 ); | ||||
|     BOOST_TEST( i2.value() == 2 ); | ||||
|     BOOST_TEST( 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 ); | ||||
|     cout << "Created MyInt objects.\n"; | ||||
|  | ||||
|     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 ); | ||||
|     PRIVATE_EXPR_TEST( (i = i2), (i.value() == 2) ); | ||||
|  | ||||
|     BOOST_TEST( i2 == i ); | ||||
|     BOOST_TEST( i1 != i2 ); | ||||
|     BOOST_TEST( i1 <  i2 ); | ||||
|     BOOST_TEST( i1 <= i2 ); | ||||
|     BOOST_TEST( i <= i2 ); | ||||
|     BOOST_TEST( i2 >  i1 ); | ||||
|     BOOST_TEST( i2 >= i1 ); | ||||
|     BOOST_TEST( i2 >= i ); | ||||
|  | ||||
|     PRIVATE_EXPR_TEST( (i = i1 + i2), (i.value() == 3) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i + i2), (i.value() == 5) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i - i1), (i.value() == 4) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i * i2), (i.value() == 8) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i / i2), (i.value() == 4) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i % ( i - i1 )), (i.value() == 1) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i2 + i2), (i.value() == 4) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i1 | i2 | i), (i.value() == 7) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i & i2), (i.value() == 2) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i + i1), (i.value() == 3) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i ^ i1), (i.value() == 2) ); | ||||
|     PRIVATE_EXPR_TEST( (i = ( i + i1 ) * ( i2 | i1 )), (i.value() == 9) ); | ||||
|  | ||||
|     PRIVATE_EXPR_TEST( (i = i1 << i2), (i.value() == 4) ); | ||||
|     PRIVATE_EXPR_TEST( (i = i2 >> i1), (i.value() == 1) ); | ||||
|      | ||||
|     cout << "Performed tests on MyInt objects.\n"; | ||||
|  | ||||
|     MyLong j1(1); | ||||
|     MyLong j2(2); | ||||
|     MyLong j; | ||||
|  | ||||
|     assert( j1.value() == 1 ); | ||||
|     assert( j2.value() == 2 ); | ||||
|     assert( j.value() == 0 ); | ||||
|     BOOST_TEST( j1.value() == 1 ); | ||||
|     BOOST_TEST( j2.value() == 2 ); | ||||
|     BOOST_TEST( 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 ); | ||||
|     cout << "Created MyLong objects.\n"; | ||||
|  | ||||
|     assert( (j1 + 2) == 3 ); | ||||
|     assert( (1 + j2) == 3 ); | ||||
|     j = j1 + j2; assert( j.value() == 3 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j2), (j.value() == 2) ); | ||||
|      | ||||
|     assert( (j + 2) == 5 ); | ||||
|     assert( (3 + j2) == 5 ); | ||||
|     j = j + j2; assert( j.value() == 5 ); | ||||
|     BOOST_TEST( j2 == j ); | ||||
|     BOOST_TEST( 2 == j ); | ||||
|     BOOST_TEST( j2 == 2 );     | ||||
|     BOOST_TEST( j == j2 ); | ||||
|     BOOST_TEST( j1 != j2 ); | ||||
|     BOOST_TEST( j1 != 2 ); | ||||
|     BOOST_TEST( 1 != j2 ); | ||||
|     BOOST_TEST( j1 <  j2 ); | ||||
|     BOOST_TEST( 1 <  j2 ); | ||||
|     BOOST_TEST( j1 <  2 ); | ||||
|     BOOST_TEST( j1 <= j2 ); | ||||
|     BOOST_TEST( 1 <= j2 ); | ||||
|     BOOST_TEST( j1 <= j ); | ||||
|     BOOST_TEST( j <= j2 ); | ||||
|     BOOST_TEST( 2 <= j2 ); | ||||
|     BOOST_TEST( j <= 2 ); | ||||
|     BOOST_TEST( j2 >  j1 ); | ||||
|     BOOST_TEST( 2 >  j1 ); | ||||
|     BOOST_TEST( j2 >  1 ); | ||||
|     BOOST_TEST( j2 >= j1 ); | ||||
|     BOOST_TEST( 2 >= j1 ); | ||||
|     BOOST_TEST( j2 >= 1 ); | ||||
|     BOOST_TEST( j2 >= j ); | ||||
|     BOOST_TEST( 2 >= j ); | ||||
|     BOOST_TEST( j2 >= 2 ); | ||||
|  | ||||
|     BOOST_TEST( (j1 + 2) == 3 ); | ||||
|     BOOST_TEST( (1 + j2) == 3 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j1 + j2), (j.value() == 3) ); | ||||
|      | ||||
|     assert( (j - 1) == 4 ); | ||||
|     j = j - j1; assert( j.value() == 4 ); | ||||
|     BOOST_TEST( (j + 2) == 5 ); | ||||
|     BOOST_TEST( (3 + j2) == 5 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j + j2), (j.value() == 5) ); | ||||
|      | ||||
|     assert( (j * 2) == 8 ); | ||||
|     assert( (4 * j2) == 8 ); | ||||
|     j = j * j2; assert( j.value() == 8 ); | ||||
|     BOOST_TEST( (j - 1) == 4 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j - j1), (j.value() == 4) ); | ||||
|      | ||||
|     assert( (j / 2) == 4 ); | ||||
|     j = j / j2; assert( j.value() == 4 ); | ||||
|     BOOST_TEST( (j * 2) == 8 ); | ||||
|     BOOST_TEST( (4 * j2) == 8 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j * j2), (j.value() == 8) ); | ||||
|      | ||||
|     assert( (j % 3) == 1 ); | ||||
|     j = j % (j - j1); assert( j.value() == 1 ); | ||||
|     BOOST_TEST( (j / 2) == 4 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j / j2), (j.value() == 4) ); | ||||
|      | ||||
|     j = j2 + j2; assert( j.value() == 4 ); | ||||
|     BOOST_TEST( (j % 3) == 1 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j % ( j - j1 )), (j.value() == 1) ); | ||||
|      | ||||
|     assert( (1 | j2 | j) == 7 ); | ||||
|     assert( (j1 | 2 | j) == 7 ); | ||||
|     assert( (j1 | j2 | 4) == 7 ); | ||||
|     j = j1 | j2 | j; assert( j.value() == 7 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j2 + j2), (j.value() == 4) ); | ||||
|      | ||||
|     assert( (7 & j2) == 2 ); | ||||
|     assert( (j & 2) == 2 ); | ||||
|     j = j & j2; assert( j.value() == 2 ); | ||||
|     BOOST_TEST( (1 | j2 | j) == 7 ); | ||||
|     BOOST_TEST( (j1 | 2 | j) == 7 ); | ||||
|     BOOST_TEST( (j1 | j2 | 4) == 7 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j1 | j2 | j), (j.value() == 7) ); | ||||
|      | ||||
|     j = j | j1; assert( j.value() == 3 ); | ||||
|     BOOST_TEST( (7 & j2) == 2 ); | ||||
|     BOOST_TEST( (j & 2) == 2 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j & j2), (j.value() == 2) ); | ||||
|      | ||||
|     assert( (3 ^ j1) == 2 ); | ||||
|     assert( (j ^ 1) == 2 ); | ||||
|     j = j ^ j1; assert( j.value() == 2 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j | j1), (j.value() == 3) ); | ||||
|      | ||||
|     j = (j+j1)*(j2|j1); assert( j.value() == 9 ); | ||||
|     BOOST_TEST( (3 ^ j1) == 2 ); | ||||
|     BOOST_TEST( (j ^ 1) == 2 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j ^ j1), (j.value() == 2) ); | ||||
|      | ||||
|     std::cout << "0 errors detected\n"; | ||||
|     return 0; | ||||
|     PRIVATE_EXPR_TEST( (j = ( j + j1 ) * ( j2 | j1 )), (j.value() == 9) ); | ||||
|  | ||||
|     BOOST_TEST( (j1 << 2) == 4 ); | ||||
|     BOOST_TEST( (j2 << 1) == 4 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j1 << j2), (j.value() == 4) ); | ||||
|  | ||||
|     BOOST_TEST( (j >> 2) == 1 ); | ||||
|     BOOST_TEST( (j2 >> 1) == 1 ); | ||||
|     PRIVATE_EXPR_TEST( (j = j2 >> j1), (j.value() == 1) ); | ||||
|      | ||||
|     cout << "Performed tests on MyLong objects.\n"; | ||||
|  | ||||
|     MyChar k1(1); | ||||
|     MyChar k2(2); | ||||
|     MyChar k; | ||||
|  | ||||
|     BOOST_TEST( k1.value() == 1 ); | ||||
|     BOOST_TEST( k2.value() == 2 ); | ||||
|     BOOST_TEST( k.value() == 0 ); | ||||
|  | ||||
|     cout << "Created MyChar objects.\n"; | ||||
|  | ||||
|     PRIVATE_EXPR_TEST( (k = k2), (k.value() == 2) ); | ||||
|  | ||||
|     BOOST_TEST( k2 == k ); | ||||
|     BOOST_TEST( k1 != k2 ); | ||||
|     BOOST_TEST( k1 <  k2 ); | ||||
|     BOOST_TEST( k1 <= k2 ); | ||||
|     BOOST_TEST( k <= k2 ); | ||||
|     BOOST_TEST( k2 >  k1 ); | ||||
|     BOOST_TEST( k2 >= k1 ); | ||||
|     BOOST_TEST( k2 >= k ); | ||||
|      | ||||
|     cout << "Performed tests on MyChar objects.\n"; | ||||
|  | ||||
|     MyShort l1(1); | ||||
|     MyShort l2(2); | ||||
|     MyShort l; | ||||
|  | ||||
|     BOOST_TEST( l1.value() == 1 ); | ||||
|     BOOST_TEST( l2.value() == 2 ); | ||||
|     BOOST_TEST( l.value() == 0 ); | ||||
|  | ||||
|     cout << "Created MyShort objects.\n"; | ||||
|  | ||||
|     PRIVATE_EXPR_TEST( (l = l2), (l.value() == 2) ); | ||||
|      | ||||
|     BOOST_TEST( l2 == l ); | ||||
|     BOOST_TEST( 2 == l ); | ||||
|     BOOST_TEST( l2 == 2 );     | ||||
|     BOOST_TEST( l == l2 ); | ||||
|     BOOST_TEST( l1 != l2 ); | ||||
|     BOOST_TEST( l1 != 2 ); | ||||
|     BOOST_TEST( 1 != l2 ); | ||||
|     BOOST_TEST( l1 <  l2 ); | ||||
|     BOOST_TEST( 1 <  l2 ); | ||||
|     BOOST_TEST( l1 <  2 ); | ||||
|     BOOST_TEST( l1 <= l2 ); | ||||
|     BOOST_TEST( 1 <= l2 ); | ||||
|     BOOST_TEST( l1 <= l ); | ||||
|     BOOST_TEST( l <= l2 ); | ||||
|     BOOST_TEST( 2 <= l2 ); | ||||
|     BOOST_TEST( l <= 2 ); | ||||
|     BOOST_TEST( l2 >  l1 ); | ||||
|     BOOST_TEST( 2 >  l1 ); | ||||
|     BOOST_TEST( l2 >  1 ); | ||||
|     BOOST_TEST( l2 >= l1 ); | ||||
|     BOOST_TEST( 2 >= l1 ); | ||||
|     BOOST_TEST( l2 >= 1 ); | ||||
|     BOOST_TEST( l2 >= l ); | ||||
|     BOOST_TEST( 2 >= l ); | ||||
|     BOOST_TEST( l2 >= 2 ); | ||||
|      | ||||
|     cout << "Performed tests on MyShort objects.\n"; | ||||
|      | ||||
|     return boost::exit_success; | ||||
| } | ||||
|   | ||||
							
								
								
									
										391
									
								
								projection_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								projection_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,391 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>Projection Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" | ||||
| align="center" width="277" height="86"> | ||||
|  | ||||
| <h1>Projection Iterator Adaptor</h1> | ||||
|  | ||||
| Defined in header | ||||
| <a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a> | ||||
|  | ||||
| <p> | ||||
| The projection iterator adaptor is similar to the <a | ||||
| href="./transform_iterator.htm">transform iterator adaptor</a> in that | ||||
| its <tt>operator*()</tt> applies some function to the result of | ||||
| dereferencing the base iterator and then returns the result. The | ||||
| difference is that the function must return a reference to some | ||||
| existing object (for example, a data member within the | ||||
| <tt>value_type</tt> of the base iterator). The following | ||||
| <b>pseudo-code</b> gives the basic idea. The data member <tt>p</tt> is | ||||
| the function object. | ||||
|  | ||||
| <pre> | ||||
|   reference projection_iterator::operator*() const { | ||||
|     return this->p(*this->base_iterator); | ||||
|   } | ||||
| </pre> | ||||
|  | ||||
| <h2>Synopsis</h2> | ||||
|  | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
|   struct projection_iterator_generator; | ||||
|    | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>,  | ||||
|             class BaseIterator, class ConstBaseIterator> | ||||
|   struct projection_iterator_pair_generator; | ||||
|  | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
|   typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type | ||||
|   make_projection_iterator(BaseIterator base, | ||||
| 			   const AdaptableUnaryFunction& p = AdaptableUnaryFunction()) | ||||
|  | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator> | ||||
|   typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type | ||||
|   make_const_projection_iterator(ConstBaseIterator base, | ||||
|                                  const AdaptableUnaryFunction& p = AdaptableUnaryFunction())   | ||||
| } | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <h2><a name="projection_iterator_generator">The Projection Iterator Type | ||||
| Generator</a></h2> | ||||
|  | ||||
| The class <tt>projection_iterator_generator</tt> is a helper class | ||||
| whose purpose is to construct an projection iterator type.  The main | ||||
| template parameter for this class is the <a | ||||
| href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a> | ||||
| function object type and the <tt>BaseIterator</tt> type that is being | ||||
| wrapped. | ||||
|  | ||||
| <pre> | ||||
| template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
| class projection_iterator_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting projection iterator type  | ||||
| }; | ||||
| </pre> | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In the following example we have a list of personnel records. Each | ||||
| record has an employee's name and ID number. We want to be able to | ||||
| traverse through the list accessing either the name or the ID numbers | ||||
| of the employees using the projection iterator so we create the | ||||
| function object classes <tt>select_name</tt> and | ||||
| <tt>select_ID</tt>. We then use the | ||||
| <tt>projection_iterator_generator</tt> class to create a projection | ||||
| iterator and use it to print out the names of the employees. | ||||
|  | ||||
| <pre> | ||||
| #include <boost/config.hpp> | ||||
| #include <list> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| struct personnel_record { | ||||
|   personnel_record(std::string n, int id) : m_name(n), m_ID(id) { } | ||||
|   std::string m_name; | ||||
|   int m_ID; | ||||
| }; | ||||
|  | ||||
| struct select_name { | ||||
|   typedef personnel_record argument_type; | ||||
|   typedef std::string result_type; | ||||
|   const std::string& operator()(const personnel_record& r) const { | ||||
|     return r.m_name; | ||||
|   } | ||||
|   std::string& operator()(personnel_record& r) const { | ||||
|     return r.m_name; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| struct select_ID { | ||||
|   typedef personnel_record argument_type; | ||||
|   typedef int result_type; | ||||
|   const int& operator()(const personnel_record& r) const { | ||||
|     return r.m_ID; | ||||
|   } | ||||
|   int& operator()(personnel_record& r) const { | ||||
|     return r.m_ID; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   std::list<personnel_record> personnel_list; | ||||
|  | ||||
|   personnel_list.push_back(personnel_record("Barney", 13423)); | ||||
|   personnel_list.push_back(personnel_record("Fred", 12343)); | ||||
|   personnel_list.push_back(personnel_record("Wilma", 62454)); | ||||
|   personnel_list.push_back(personnel_record("Betty", 20490)); | ||||
|  | ||||
|   // Example of using projection_iterator_generator | ||||
|   // to print out the names in the personnel list. | ||||
|  | ||||
|   boost::projection_iterator_generator<select_name, | ||||
|     std::list<personnel_record>::iterator>::type | ||||
|     personnel_first(personnel_list.begin()), | ||||
|     personnel_last(personnel_list.end()); | ||||
|  | ||||
|   std::copy(personnel_first, personnel_last, | ||||
|             std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // to be continued... | ||||
| </pre> | ||||
| The output for this part is: | ||||
| <pre> | ||||
| Barney | ||||
| Fred | ||||
| Wilma | ||||
| Betty | ||||
| </pre> | ||||
|  | ||||
| <h3>Template Parameters</h3> | ||||
|  | ||||
| <Table border> | ||||
| <TR> | ||||
| <TH>Parameter</TH><TH>Description</TH> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD> | ||||
| <TD>The type of the function object. The <tt>argument_type</tt> of the | ||||
| function must match the value type of the base iterator. The function | ||||
| should return a reference to the function's <tt>result_type</tt>. | ||||
| The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>. | ||||
| </TD> | ||||
| </TD> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>BaseIterator</tt></TD> | ||||
| <TD>The iterator type being wrapped.</TD> | ||||
| </TD> | ||||
| </TR> | ||||
|  | ||||
| </Table> | ||||
|  | ||||
| <h3>Model of</h3> | ||||
|  | ||||
| If the base iterator is a model of <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> then so is the resulting projection iterator.  If | ||||
| the base iterator supports less functionality than this the resulting | ||||
| projection iterator will also support less functionality. | ||||
|  | ||||
| <h3>Members</h3> | ||||
|  | ||||
| The projection iterator type implements the member functions and | ||||
| operators required of the <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> concept. | ||||
| In addition it has the following constructor: | ||||
|  | ||||
| <pre> | ||||
| projection_iterator_generator::type(const BaseIterator& it, | ||||
|                                     const AdaptableUnaryFunction& p = AdaptableUnaryFunction()) | ||||
| </pre> | ||||
|  | ||||
| <p> | ||||
| <hr> | ||||
| <p> | ||||
|  | ||||
| <h2><a name="projection_iterator_pair_generator">The Projection Iterator Pair | ||||
| Generator</a></h2> | ||||
|  | ||||
| Sometimes a mutable/const pair of iterator types is needed, such as | ||||
| when implementing a container type. The | ||||
| <tt>projection_iterator_pair_generator</tt> class makes it more | ||||
| convenient to create this pair of iterator types. | ||||
|  | ||||
| <pre> | ||||
| template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator, class ConstBaseIterator> | ||||
| class projection_iterator_pair_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> iterator;       // the mutable projection iterator type  | ||||
|   typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> const_iterator; // the immutable projection iterator type  | ||||
| }; | ||||
| </pre> | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In this part of the example we use the | ||||
| <tt>projection_iterator_pair_generator</tt> to create a mutable/const | ||||
| pair of projection iterators that access the ID numbers of the | ||||
| personnel. We use the mutable iterator to re-index the ID numbers from | ||||
| zero. We then use the constant iterator to print the ID numbers out. | ||||
|  | ||||
| <pre> | ||||
|   // continuing from the last example... | ||||
|  | ||||
|   typedef boost::projection_iterator_pair_generator<select_ID, | ||||
|     std::list<personnel_record>::iterator, | ||||
|     std::list<personnel_record>::const_iterator> PairGen; | ||||
|  | ||||
|   PairGen::iterator ID_first(personnel_list.begin()), | ||||
|     ID_last(personnel_list.end()); | ||||
|  | ||||
|   int new_id = 0; | ||||
|   while (ID_first != ID_last) { | ||||
|     *ID_first = new_id++; | ||||
|     ++ID_first; | ||||
|   } | ||||
|  | ||||
|   PairGen::const_iterator const_ID_first(personnel_list.begin()), | ||||
|     const_ID_last(personnel_list.end()); | ||||
|  | ||||
|   std::copy(const_ID_first, const_ID_last, | ||||
|             std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   // to be continued... | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| 0 1 2 3  | ||||
| </pre> | ||||
|  | ||||
| <h3>Template Parameters</h3> | ||||
|  | ||||
| <Table border> | ||||
| <TR> | ||||
| <TH>Parameter</TH><TH>Description</TH> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD> | ||||
| <TD>The type of the function object. The <tt>argument_type</tt> of the | ||||
| function must match the value type of the base iterator. The function | ||||
| should return a true reference to the function's <tt>result_type</tt>. | ||||
| The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>. | ||||
| </TD> | ||||
| </TD> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>BaseIterator</tt></TD> | ||||
| <TD>The mutable iterator type being wrapped.</TD> | ||||
| </TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>ConstBaseIterator</tt></TD> | ||||
| <TD>The constant iterator type being wrapped.</TD> | ||||
| </TD> | ||||
| </TR> | ||||
|  | ||||
| </Table> | ||||
|  | ||||
| <h3>Model of</h3> | ||||
|  | ||||
| If the base iterator types model the <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> then so do the resulting projection iterator | ||||
| types.  If the base iterators support less functionality the | ||||
| resulting projection iterator types will also support less | ||||
| functionality.  The resulting <tt>iterator</tt> type is mutable, and | ||||
| the resulting <tt>const_iterator</tt> type is constant. | ||||
|  | ||||
| <h3>Members</h3> | ||||
|  | ||||
| The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types | ||||
| implements the member functions and operators required of the <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random | ||||
| Access Iterator</a> concept.  In addition they support the following | ||||
| constructors: | ||||
|  | ||||
| <pre> | ||||
| projection_iterator_pair_generator::iterator(const BaseIterator& it, | ||||
|                                              const AdaptableUnaryFunction& p = AdaptableUnaryFunction())</pre> | ||||
|  | ||||
| <pre> | ||||
| projection_iterator_pair_generator::const_iterator(const BaseIterator& it, | ||||
|                                                    const AdaptableUnaryFunction& p = AdaptableUnaryFunction()) | ||||
| </pre> | ||||
|  | ||||
| <p> | ||||
| <hr> | ||||
| <p> | ||||
|  | ||||
| <h2><a name="make_projection_iterator">The Projection Iterator Object Generators</a></h2> | ||||
|  | ||||
| The <tt>make_projection_iterator()</tt> and | ||||
| <tt>make_const_projection_iterator()</tt> functions provide a more | ||||
| convenient way to create projection iterator objects. The functions | ||||
| save the user the trouble of explicitly writing out the iterator | ||||
| types. | ||||
|  | ||||
| <pre> | ||||
| template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
| typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type | ||||
| make_projection_iterator(BaseIterator base, | ||||
| 			 const AdaptableUnaryFunction& p = AdaptableUnaryFunction())   | ||||
|  | ||||
| template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator> | ||||
| typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type | ||||
| make_const_projection_iterator(ConstBaseIterator base, | ||||
| 			       const AdaptableUnaryFunction& p = AdaptableUnaryFunction())   | ||||
| </pre> | ||||
|  | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| In this part of the example, we again print out the names of the | ||||
| personnel, but this time we use the | ||||
| <tt>make_const_projection_iterator()</tt> function to save some typing. | ||||
|  | ||||
| <pre> | ||||
|   // continuing from the last example... | ||||
|  | ||||
|   std::copy | ||||
|     (boost::make_const_projection_iterator<select_name>(personnel_list.begin()), | ||||
|      boost::make_const_projection_iterator<select_name>(personnel_list.end()), | ||||
|      std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
| The output is: | ||||
| <pre> | ||||
| Barney | ||||
| Fred | ||||
| Wilma | ||||
| Betty | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p> | ||||
| <p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use, | ||||
| modify, sell and distribute this document is granted provided this copyright | ||||
| notice appears in all copies. This document is provided "as is" | ||||
| without express or implied warranty, and with no claim as to its suitability for | ||||
| any purpose.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
| <!--  LocalWords:  html charset alt gif hpp BaseIterator const namespace struct | ||||
|  --> | ||||
| <!--  LocalWords:  ConstPointer ConstReference typename iostream int abcdefg | ||||
|  --> | ||||
| <!--  LocalWords:  sizeof  PairGen pre Siek htm AdaptableUnaryFunction | ||||
|  --> | ||||
| <!--  LocalWords:  ConstBaseIterator | ||||
|  --> | ||||
							
								
								
									
										96
									
								
								projection_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								projection_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| // (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears | ||||
| // in all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <list> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| struct personnel_record { | ||||
|   personnel_record(std::string n, int id) : m_name(n), m_ID(id) { } | ||||
|   std::string m_name; | ||||
|   int m_ID; | ||||
| }; | ||||
|  | ||||
| struct select_name { | ||||
|   typedef personnel_record argument_type; | ||||
|   typedef std::string result_type; | ||||
|   const std::string& operator()(const personnel_record& r) const { | ||||
|     return r.m_name; | ||||
|   } | ||||
|   std::string& operator()(personnel_record& r) const { | ||||
|     return r.m_name; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| struct select_ID { | ||||
|   typedef personnel_record argument_type; | ||||
|   typedef int result_type; | ||||
|   const int& operator()(const personnel_record& r) const { | ||||
|     return r.m_ID; | ||||
|   } | ||||
|   int& operator()(personnel_record& r) const { | ||||
|     return r.m_ID; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   std::list<personnel_record> personnel_list; | ||||
|  | ||||
|   personnel_list.push_back(personnel_record("Barney", 13423)); | ||||
|   personnel_list.push_back(personnel_record("Fred", 12343)); | ||||
|   personnel_list.push_back(personnel_record("Wilma", 62454)); | ||||
|   personnel_list.push_back(personnel_record("Betty", 20490)); | ||||
|  | ||||
|   // Example of using projection_iterator_generator | ||||
|   // to print out the names in the personnel list. | ||||
|  | ||||
|   boost::projection_iterator_generator<select_name, | ||||
|     std::list<personnel_record>::iterator>::type | ||||
|     personnel_first(personnel_list.begin()), | ||||
|     personnel_last(personnel_list.end()); | ||||
|  | ||||
|   std::copy(personnel_first, personnel_last, | ||||
|             std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   // Example of using projection_iterator_pair_generator | ||||
|   // to assign new ID numbers to the personnel. | ||||
|    | ||||
|   typedef boost::projection_iterator_pair_generator<select_ID, | ||||
|     std::list<personnel_record>::iterator, | ||||
|     std::list<personnel_record>::const_iterator> PairGen; | ||||
|  | ||||
|   PairGen::iterator ID_first(personnel_list.begin()), | ||||
|     ID_last(personnel_list.end()); | ||||
|  | ||||
|   int new_id = 0; | ||||
|   while (ID_first != ID_last) { | ||||
|     *ID_first = new_id++; | ||||
|     ++ID_first; | ||||
|   } | ||||
|  | ||||
|   PairGen::const_iterator const_ID_first(personnel_list.begin()), | ||||
|     const_ID_last(personnel_list.end()); | ||||
|  | ||||
|   std::copy(const_ID_first, const_ID_last, | ||||
|             std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   // Example of using make_const_projection_iterator() | ||||
|   // to print out the names in the personnel list again. | ||||
|    | ||||
|   std::copy | ||||
|     (boost::make_const_projection_iterator<select_name>(personnel_list.begin()), | ||||
|      boost::make_const_projection_iterator<select_name>(personnel_list.end()), | ||||
|      std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										331
									
								
								reverse_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								reverse_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,331 @@ | ||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> | ||||
|  | ||||
| <html> | ||||
| <head> | ||||
|     <meta name="generator" content="HTML Tidy, see www.w3.org"> | ||||
|     <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
|     <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
|     <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
|  | ||||
|     <title>Reverse Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|     <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align= | ||||
|     "center" width="277" height="86">  | ||||
|  | ||||
|     <h1>Reverse Iterator Adaptor</h1> | ||||
|     Defined in header <a href= | ||||
|     "../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>  | ||||
|  | ||||
|     <p>The reverse iterator adaptor flips the direction of a base iterator's | ||||
|     motion. Invoking <tt>operator++()</tt> moves the base iterator backward and | ||||
|     invoking <tt>operator--()</tt> moves the base iterator forward. The Boost | ||||
|     reverse iterator adaptor is better to use than the | ||||
|     <tt>std::reverse_iterator</tt> class in situations where pairs of | ||||
|     mutable/constant iterators are needed (e.g., in containers) because | ||||
|     comparisons and conversions between the mutable and const versions are | ||||
|     implemented correctly. | ||||
|  | ||||
|     <h2>Synopsis</h2> | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class <a href= | ||||
| "http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>, | ||||
|             class Value, class Reference, class Pointer, class Category, class Distance> | ||||
|   struct reverse_iterator_generator; | ||||
|    | ||||
|   template <class <a href= | ||||
| "http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>> | ||||
|   typename reverse_iterator_generator<BidirectionalIterator>::type | ||||
|   make_reverse_iterator(BidirectionalIterator base)   | ||||
| } | ||||
| </pre> | ||||
|     <hr> | ||||
|  | ||||
|     <h2><a name="reverse_iterator_generator">The Reverse Iterator Type | ||||
|     Generator</a></h2> | ||||
|     The <tt>reverse_iterator_generator</tt> template is a <a href= | ||||
|     "../../more/generic_programming.html#type_generator">generator</a> of | ||||
|     reverse iterator types. The main template parameter for this class is the | ||||
|     base <tt>BidirectionalIterator</tt> type that is being adapted. In most | ||||
|     cases the associated types of the base iterator can be deduced using | ||||
|     <tt>std::iterator_traits</tt>, but in some situations the user may want to | ||||
|     override these types, so there are also template parameters for the base | ||||
|     iterator's associated types.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class <a href= | ||||
| "http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>, | ||||
|           class Value, class Reference, class Pointer, class Category, class Distance> | ||||
| class reverse_iterator_generator | ||||
| { | ||||
| public: | ||||
|   typedef <tt><a href= | ||||
| "./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting reverse iterator type  | ||||
| }; | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|     In this example we sort a sequence of letters and then output the sequence | ||||
|     in descending order using reverse iterators.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   char letters[] = "hello world!"; | ||||
|   const int N = sizeof(letters)/sizeof(char) - 1; | ||||
|   std::cout << "original sequence of letters:\t" | ||||
|       << letters << std::endl; | ||||
|  | ||||
|   std::sort(letters, letters + N); | ||||
|  | ||||
|   // Use reverse_iterator_generator to print a sequence | ||||
|   // of letters in reverse order. | ||||
|    | ||||
|   boost::reverse_iterator_generator<char*>::type | ||||
|     reverse_letters_first(letters + N), | ||||
|     reverse_letters_last(letters); | ||||
|  | ||||
|   std::cout << "letters in descending order:\t"; | ||||
|   std::copy(reverse_letters_first, reverse_letters_last, | ||||
|       std::ostream_iterator<char>(std::cout)); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // to be continued... | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     The output is:  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| original sequence of letters: hello world! | ||||
| letters in descending order:  wroolllhed!  | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Template Parameters</h3> | ||||
|  | ||||
|     <table border> | ||||
|       <tr> | ||||
|         <th>Parameter | ||||
|  | ||||
|         <th>Description | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt><a href= | ||||
|         "http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a></tt> | ||||
|          | ||||
|  | ||||
|         <td>The iterator type being wrapped. | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Value</tt>  | ||||
|  | ||||
|         <td>The value-type of the base iterator and the resulting reverse | ||||
|         iterator.<br> | ||||
|          <b>Default:</b><tt>std::iterator_traits<BidirectionalIterator>::value_type</tt> | ||||
|          | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Reference</tt>  | ||||
|  | ||||
|         <td>The <tt>reference</tt> type of the resulting iterator, and in | ||||
|         particular, the result type of <tt>operator*()</tt>.<br> | ||||
|          <b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&</tt> is | ||||
|         used. Otherwise | ||||
|         <tt>std::iterator_traits<BidirectionalIterator>::reference</tt> | ||||
|         is used. | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Pointer</tt>  | ||||
|  | ||||
|         <td>The <tt>pointer</tt> type of the resulting iterator, and in | ||||
|         particular, the result type of <tt>operator->()</tt>.<br> | ||||
|          <b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>, | ||||
|         otherwise | ||||
|         <tt>std::iterator_traits<BidirectionalIterator>::pointer</tt>. | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Category</tt>  | ||||
|  | ||||
|         <td>The <tt>iterator_category</tt> type for the resulting iterator.<br> | ||||
|          <b>Default:</b> | ||||
|         <tt>std::iterator_traits<BidirectionalIterator>::iterator_category</tt> | ||||
|          | ||||
|  | ||||
|       <tr> | ||||
|         <td><tt>Distance</tt>  | ||||
|  | ||||
|         <td>The <tt>difference_type</tt> for the resulting iterator.<br> | ||||
|          <b>Default:</b> | ||||
|         <tt>std::iterator_traits<BidirectionalIterator&gt::difference_type</tt> | ||||
|          | ||||
|     </table> | ||||
|  | ||||
|     <h3>Concept Model</h3> | ||||
|     The indirect iterator will model whichever <a href= | ||||
|     "http://www.sgi.com/tech/stl/Iterators.html">standard iterator concept | ||||
|     category</a> is modeled by the base iterator. Thus, if the base iterator is | ||||
|     a model of <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access | ||||
|     Iterator</a> then so is the resulting indirect iterator. If the base | ||||
|     iterator models a more restrictive concept, the resulting indirect iterator | ||||
|     will model the same concept. The base iterator must be at least a <a href= | ||||
|     "http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional | ||||
|     Iterator</a>  | ||||
|  | ||||
|     <h3>Members</h3> | ||||
|     The reverse iterator type implements the member functions and operators | ||||
|     required of the <a href= | ||||
|     "http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access | ||||
|     Iterator</a> concept. In addition it has the following constructor:  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| reverse_iterator_generator::type(const BidirectionalIterator& it) | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|  | ||||
|     <br> | ||||
|      <br> | ||||
|       | ||||
|     <hr> | ||||
|  | ||||
|     <p> | ||||
|  | ||||
|     <h2><a name="make_reverse_iterator">The Reverse Iterator Object | ||||
|     Generator</a></h2> | ||||
|     The <tt>make_reverse_iterator()</tt> function provides a more convenient | ||||
|     way to create reverse iterator objects. The function saves the user the | ||||
|     trouble of explicitly writing out the iterator types.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| template <class BidirectionalIterator> | ||||
| typename reverse_iterator_generator<BidirectionalIterator>::type | ||||
| make_reverse_iterator(BidirectionalIterator base); | ||||
| </pre> | ||||
|     </blockquote> | ||||
|  | ||||
|     <h3>Example</h3> | ||||
|     In this part of the example we use <tt>make_reverse_iterator()</tt> to | ||||
|     print the sequence of letters in reverse-reverse order, which is the | ||||
|     original order.  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
|   // continuing from the previous example... | ||||
|  | ||||
|   std::cout << "letters in ascending order:\t"; | ||||
|   std::copy(boost::make_reverse_iterator(reverse_letters_last), | ||||
|       boost::make_reverse_iterator(reverse_letters_first), | ||||
|       std::ostream_iterator<char>(std::cout)); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     The output is:  | ||||
|  | ||||
|     <blockquote> | ||||
| <pre> | ||||
| letters in ascending order:  !dehllloorw | ||||
| </pre> | ||||
|     </blockquote> | ||||
|     <hr> | ||||
|  | ||||
|     <h2><a name="interactions">Constant/Mutable Iterator Interactions</a></h2> | ||||
|  | ||||
|     <p>One failing of the standard <tt><a | ||||
|     href="http://www.sgi.com/tech/stl/ReverseIterator.html">reverse_iterator</a></tt> | ||||
|     adaptor is that it doesn't properly support interactions between adapted | ||||
|     <tt>const</tt> and non-<tt>const</tt> iterators. For example: | ||||
| <blockquote> | ||||
| <pre> | ||||
| #include <vector> | ||||
|  | ||||
| template <class T> void convert(T x) {} | ||||
|  | ||||
| // Test interactions of a matched pair of random access iterators | ||||
| template <class Iterator, class ConstIterator> | ||||
| void test_interactions(Iterator i, ConstIterator ci) | ||||
| { | ||||
|   bool eq = i == ci;               // comparisons | ||||
|   bool ne = i != ci;             | ||||
|   bool lt = i < ci; | ||||
|   bool le = i <= ci; | ||||
|   bool gt = i > ci; | ||||
|   bool ge = i >= ci; | ||||
|   std::size_t distance = i - ci;   // difference | ||||
|   ci = i;                          // assignment | ||||
|   ConstIterator ci2(i);            // construction | ||||
|   convert<ConstIterator>(i);       // implicit conversion | ||||
| } | ||||
|  | ||||
| void f() | ||||
| { | ||||
|   typedef std::vector<int> vec; | ||||
|   vec v; | ||||
|   const vec& cv; | ||||
|  | ||||
|   test_interactions(v.begin(), cv.begin());   // <font color="#007F00">OK</font> | ||||
|   test_interactions(v.rbegin(), cv.rbegin()); // <font color="#FF0000">ERRORS ON EVERY TEST!!</font> | ||||
| </pre> | ||||
| </blockquote> | ||||
| Reverse iterators created with <tt>boost::reverse_iterator_generator</tt> don't have this problem, though: | ||||
| <blockquote> | ||||
| <pre> | ||||
|   typedef boost::reverse_iterator_generator<vec::iterator>::type ri; | ||||
|   typedef boost::reverse_iterator_generator<vec::const_iterator>::type cri; | ||||
|   test_interactions(ri(v.begin()), cri(cv.begin()));   // <font color="#007F00">OK!!</font> | ||||
| </pre> | ||||
| </blockquote> | ||||
| Or, more simply, | ||||
| <blockquote> | ||||
| <pre> | ||||
|   test_interactions( | ||||
|     boost::make_reverse_iterator(v.begin()),  | ||||
|     boost::make_reverse_iterator(cv.begin()));   // <font color="#007F00">OK!!</font> | ||||
| } | ||||
| </pre> | ||||
| </blockquote> | ||||
|  | ||||
| <p>If you are wondering why there is no | ||||
| <tt>reverse_iterator_pair_generator</tt> in the manner of <tt><a | ||||
| href="projection_iterator.htm#projection_iterator_pair_generator">projection_iterator_pair_generator</a></tt>, | ||||
| the answer is simple: we tried it, but found that in practice it took | ||||
| <i>more</i> typing to use <tt>reverse_iterator_pair_generator</tt> than to | ||||
| simply use <tt>reverse_iterator_generator</tt> twice!<br><br> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
|      | ||||
|     <p>Revised  | ||||
|     <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --> | ||||
|  | ||||
|  | ||||
|     <p>© Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell | ||||
|     and distribute this document is granted provided this copyright notice | ||||
|     appears in all copies. This document is provided "as is" without express or | ||||
|     implied warranty, and with no claim as to its suitability for any purpose.  | ||||
|     <!--  LocalWords:  html charset alt gif hpp BidirectionalIterator const namespace struct | ||||
|          --> | ||||
|       | ||||
|     <!--  LocalWords:  ConstPointer ConstReference typename iostream int abcdefg | ||||
|          --> | ||||
|      <!--  LocalWords:  sizeof  PairGen pre Siek wroolllhed dehllloorw | ||||
|          --> | ||||
| </body> | ||||
| </html> | ||||
|  | ||||
							
								
								
									
										42
									
								
								reverse_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								reverse_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| // (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears | ||||
| // in all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| int main(int, char*[]) | ||||
| { | ||||
|   char letters[] = "hello world!"; | ||||
|   const int N = sizeof(letters)/sizeof(char) - 1; | ||||
|   std::cout << "original sequence of letters:\t" | ||||
| 	    << letters << std::endl; | ||||
|  | ||||
|   std::sort(letters, letters + N); | ||||
|  | ||||
|   // Use reverse_iterator_generator to print a sequence | ||||
|   // of letters in reverse order. | ||||
|    | ||||
|   boost::reverse_iterator_generator<char*>::type | ||||
|     reverse_letters_first(letters + N), | ||||
|     reverse_letters_last(letters); | ||||
|  | ||||
|   std::cout << "letters in descending order:\t"; | ||||
|   std::copy(reverse_letters_first, reverse_letters_last, | ||||
| 	    std::ostream_iterator<char>(std::cout)); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // Use make_reverse_iterator() to print the sequence | ||||
|   // of letters in reverse-reverse order. | ||||
|  | ||||
|   std::cout << "letters in ascending order:\t"; | ||||
|   std::copy(boost::make_reverse_iterator(reverse_letters_last), | ||||
| 	    boost::make_reverse_iterator(reverse_letters_first), | ||||
| 	    std::ostream_iterator<char>(std::cout)); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										2
									
								
								tie.html
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tie.html
									
									
									
									
									
								
							| @@ -64,7 +64,7 @@ pair of iterators is assigned to the iterator variables <TT>i</TT> and | ||||
|  | ||||
| <P> | ||||
| Here is another example that uses <TT>tie()</TT> for handling operations with <a | ||||
| href="http://www.sgi.com/Technology/STL/set.html"><TT>std::set</TT></a>. | ||||
| href="http://www.sgi.com/tech/stl/set.html"><TT>std::set</TT></a>. | ||||
|  | ||||
| <P> | ||||
| <PRE> | ||||
|   | ||||
							
								
								
									
										223
									
								
								transform_iterator.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								transform_iterator.htm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> | ||||
| <meta name="ProgId" content="FrontPage.Editor.Document"> | ||||
| <title>Transform Iterator Adaptor Documentation</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" text="#000000"> | ||||
|  | ||||
| <img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" | ||||
| align="center" width="277" height="86"> | ||||
|  | ||||
| <h1>Transform Iterator Adaptor</h1> | ||||
|  | ||||
| Defined in header | ||||
| <a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a> | ||||
|  | ||||
| <p> | ||||
| The transform iterator adaptor augments an iterator by applying some | ||||
| function object to the result of dereferencing the iterator. Another | ||||
| words, the <tt>operator*</tt> of the transform iterator first | ||||
| dereferences the base iterator, passes the result of this to the | ||||
| function object, and then returns the result. The following | ||||
| <b>pseudo-code</b> shows the basic idea: | ||||
|  | ||||
| <pre> | ||||
|   value_type transform_iterator::operator*() const { | ||||
|     return this->f(*this->base_iterator); | ||||
|   } | ||||
| </pre> | ||||
|  | ||||
| All of the other operators of the transform iterator behave in the | ||||
| same fashion as those of the base iterator. | ||||
|  | ||||
|  | ||||
| <h2>Synopsis</h2> | ||||
|  | ||||
| <pre> | ||||
| namespace boost { | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
|   class transform_iterator_generator; | ||||
|  | ||||
|   template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator> | ||||
|   typename transform_iterator_generator<AdaptableUnaryFunction,Iterator>::type | ||||
|   make_transform_iterator(BaseIterator base, const AdaptableUnaryFunction& f = AdaptableUnaryFunction()); | ||||
| } | ||||
| </pre> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <h2><a name="transform_iterator_generator">The Transform Iterator Type | ||||
| Generator</a></h2> | ||||
|  | ||||
| The class <tt>transform_iterator_generator</tt> is a helper class whose | ||||
| purpose is to construct a transform iterator type.  The template | ||||
| parameters for this class are the <tt>AdaptableUnaryFunction</tt> function object | ||||
| type and the <tt>BaseIterator</tt> type that is being wrapped. | ||||
|  | ||||
| <pre> | ||||
| template <class AdaptableUnaryFunction, class Iterator> | ||||
| class transform_iterator_generator | ||||
| { | ||||
| public: | ||||
|     typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...> type; | ||||
| }; | ||||
| </pre> | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| <p> | ||||
| The following is an example of how to use the | ||||
| <tt>transform_iterator_generator</tt> class to iterate through a range | ||||
| of numbers, multiplying each of them by 2 when they are dereferenced. | ||||
| The <tt>boost::binder1st</tt> class is used instead of the standard | ||||
| one because tranform iterator requires the function object to be | ||||
| Default Constructible. | ||||
|  | ||||
| <p> | ||||
| <PRE> | ||||
| #include <functional> | ||||
| #include <iostream> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| // definition of class boost::binder1st and function boost::bind1st() ... | ||||
|  | ||||
| int | ||||
| main(int, char*[]) | ||||
| { | ||||
|   int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | ||||
|  | ||||
|   typedef boost::binder1st< std::multiplies<int> > Function; | ||||
|   typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator; | ||||
|  | ||||
|   doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)), | ||||
|     i_end(x + sizeof(x)/sizeof(int), boost::bind1st(std::multiplies<int>(), 2)); | ||||
|  | ||||
|   std::cout << "multiplying the array by 2:" << std::endl; | ||||
|   while (i != i_end) | ||||
|     std::cout << *i++ << " "; | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   // to be continued... | ||||
| </PRE> | ||||
| The output from this part is: | ||||
| <pre> | ||||
| 2 4 6 8 10 12 14 16 | ||||
| </pre> | ||||
|  | ||||
| <h3>Template Parameters</h3> | ||||
|  | ||||
| <Table border> | ||||
| <TR> | ||||
| <TH>Parameter</TH><TH>Description</TH> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><a | ||||
| href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD> | ||||
| <TD>The function object that transforms each element in the iterator | ||||
| range.  The <tt>argument_type</tt> of the function object must match | ||||
| the value type of the base iterator.  The <tt>result_type</tt> of the | ||||
| function object will be the resulting iterator's | ||||
| <tt>value_type</tt>. If you want the resulting iterator to behave as | ||||
| an iterator, the result of the function should be solely a function of | ||||
| its argument. Also, the function object must be <a | ||||
| href="http://www.sgi.com/tech/stl/DefaultConstructible.html"> Default | ||||
| Constructible</a> (which many of the standard function objects are not).</TD> | ||||
| </TR> | ||||
|  | ||||
| <TR> | ||||
| <TD><tt>BaseIterator</tt></TD> | ||||
| <TD>The iterator type being wrapped. This type must at least be a model | ||||
|  of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD> | ||||
| </TR> | ||||
|  | ||||
| </Table> | ||||
|  | ||||
| <h3>Model of</h3> | ||||
|  | ||||
| The transform iterator adaptor (the type | ||||
| <tt>transform_iterator_generator<...>::type</tt>) is a model of <a | ||||
| href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a><a href="#1">[1]</a>. | ||||
|  | ||||
|  | ||||
| <h3>Members</h3> | ||||
|  | ||||
| The transform iterator type implements the member functions and | ||||
| operators required of the <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a> | ||||
| concept, except that the <tt>reference</tt> type is the same as the <tt>value_type</tt> | ||||
| so <tt>operator*()</tt> returns by-value. In addition it has the following constructor: | ||||
|  | ||||
| <pre> | ||||
| transform_iterator_generator::type(const BaseIterator& it, | ||||
|                                    const AdaptableUnaryFunction& f = AdaptableUnaryFunction()) | ||||
| </pre> | ||||
|  | ||||
| <p> | ||||
| <hr> | ||||
| <p> | ||||
|  | ||||
|  | ||||
| <h2><a name="make_transform_iterator">The Transform Iterator Object Generator</a></h2> | ||||
|  | ||||
| <pre> | ||||
| template <class AdaptableUnaryFunction, class BaseIterator> | ||||
| typename transform_iterator_generator<AdaptableUnaryFunction,BaseIterator>::type | ||||
| make_transform_iterator(BaseIterator base, | ||||
|                         const AdaptableUnaryFunction& f = AdaptableUnaryFunction()); | ||||
| </pre> | ||||
|  | ||||
| This function provides a convenient way to create transform iterators. | ||||
|  | ||||
| <h3>Example</h3> | ||||
|  | ||||
| Continuing from the previous example, we use the <tt>make_transform_iterator()</tt> | ||||
| function to add four to each element of the array. | ||||
|  | ||||
| <pre> | ||||
|   std::cout << "adding 4 to each element in the array:" << std::endl; | ||||
|  | ||||
|   std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)), | ||||
| 	    boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| </pre> | ||||
| The output from this part is: | ||||
| <pre> | ||||
| 5 6 7 8 9 10 11 12 | ||||
| </pre> | ||||
|  | ||||
| <h3>Notes</h3> | ||||
|  | ||||
|  | ||||
| <a name="1">[1]</a> If the base iterator is a model of <a | ||||
| href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access Iterator</a> | ||||
| then the transform iterator will also suppport most of the | ||||
| functionality required by the Random Access Iterator concept. However, a | ||||
| transform iterator can never completely satisfy the requirements for | ||||
| <a | ||||
| href="http://www.sgi.com/tech/stl/ForwardIterator.html">Forward Iterator</a> | ||||
| (or of any concepts that refine Forward Iterator, which includes | ||||
| Random Access Iterator and Bidirectional Iterator) since the <tt>operator*</tt> of the transform | ||||
| iterator always returns by-value. | ||||
|  | ||||
|  | ||||
|  | ||||
| <hr> | ||||
| <p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->29 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14896" --></p> | ||||
| <p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use, | ||||
| modify, sell and distribute this document is granted provided this copyright | ||||
| notice appears in all copies. This document is provided "as is" | ||||
| without express or implied warranty, and with no claim as to its suitability for | ||||
| any purpose.</p> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										76
									
								
								transform_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								transform_iterator_example.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| // (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and | ||||
| // distribute this software is granted provided this copyright notice appears | ||||
| // in all copies. This software is provided "as is" without express or implied | ||||
| // warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
|  | ||||
| #include <functional> | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
|  | ||||
| // What a bummer. We can't use std::binder1st with transform iterator | ||||
| // because it does not have a default constructor. Here's a version | ||||
| // that does. | ||||
|  | ||||
| namespace boost { | ||||
|  | ||||
|   template <class Operation>  | ||||
|   class binder1st | ||||
|     : public std::unary_function<typename Operation::second_argument_type, | ||||
| 			         typename Operation::result_type> { | ||||
|   protected: | ||||
|     Operation op; | ||||
|     typename Operation::first_argument_type value; | ||||
|   public: | ||||
|     binder1st() { } // this had to be added! | ||||
|     binder1st(const Operation& x, | ||||
| 	      const typename Operation::first_argument_type& y) | ||||
| 	: op(x), value(y) {} | ||||
|     typename Operation::result_type | ||||
|     operator()(const typename Operation::second_argument_type& x) const { | ||||
|       return op(value, x);  | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   template <class Operation, class T> | ||||
|   inline binder1st<Operation> bind1st(const Operation& op, const T& x) { | ||||
|     typedef typename Operation::first_argument_type arg1_type; | ||||
|     return binder1st<Operation>(op, arg1_type(x)); | ||||
|   } | ||||
|  | ||||
| } // namespace boost | ||||
|  | ||||
| int | ||||
| main(int, char*[]) | ||||
| { | ||||
|   // This is a simple example of using the transform_iterators class to | ||||
|   // generate iterators that multiply the value returned by dereferencing | ||||
|   // the iterator. In this case we are multiplying by 2. | ||||
|   // Would be cooler to use lambda library in this example. | ||||
|  | ||||
|   int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | ||||
|   const int N = sizeof(x)/sizeof(int); | ||||
|  | ||||
|   typedef boost::binder1st< std::multiplies<int> > Function; | ||||
|   typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator; | ||||
|  | ||||
|   doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)), | ||||
|     i_end(x + N, boost::bind1st(std::multiplies<int>(), 2)); | ||||
|  | ||||
|   std::cout << "multiplying the array by 2:" << std::endl; | ||||
|   while (i != i_end) | ||||
|     std::cout << *i++ << " "; | ||||
|   std::cout << std::endl; | ||||
|  | ||||
|   std::cout << "adding 4 to each element in the array:" << std::endl; | ||||
|  | ||||
|   std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)), | ||||
| 	    boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)), | ||||
| 	    std::ostream_iterator<int>(std::cout, " ")); | ||||
|   std::cout << std::endl; | ||||
|    | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										54
									
								
								transform_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								transform_iterator_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| //  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify, | ||||
| //  sell and distribute this software is granted provided this | ||||
| //  copyright notice appears in all copies. This software is provided | ||||
| //  "as is" without express or implied warranty, and with no claim as | ||||
| //  to its suitability for any purpose. | ||||
|  | ||||
| //  Revision History | ||||
| //  08 Mar 2001   Jeremy Siek | ||||
| //       Moved test of transform iterator into its own file. It to | ||||
| //       to be in iterator_adaptor_test.cpp. | ||||
|  | ||||
| #include <boost/config.hpp> | ||||
| #include <iostream> | ||||
| #include <algorithm> | ||||
| #include <boost/iterator_adaptors.hpp> | ||||
| #include <boost/pending/iterator_tests.hpp> | ||||
|  | ||||
| struct mult_functor { | ||||
|   typedef int result_type; | ||||
|   typedef int argument_type; | ||||
|   // Functors used with transform_iterator must be | ||||
|   // DefaultConstructible, as the transform_iterator must be | ||||
|   // DefaultConstructible to satisfy the requirements for | ||||
|   // TrivialIterator. | ||||
|   mult_functor() { } | ||||
|   mult_functor(int aa) : a(aa) { } | ||||
|   int operator()(int b) const { return a * b; } | ||||
|   int a; | ||||
| }; | ||||
|  | ||||
| int | ||||
| main() | ||||
| { | ||||
|   const int N = 10; | ||||
|  | ||||
|   // Borland is getting confused about typedef's and constructors here | ||||
|  | ||||
|   // Test transform_iterator | ||||
|   { | ||||
|     int x[N], y[N]; | ||||
|     for (int k = 0; k < N; ++k) | ||||
|       x[k] = k; | ||||
|     std::copy(x, x + N, y); | ||||
|  | ||||
|     for (int k2 = 0; k2 < N; ++k2) | ||||
|       x[k2] = x[k2] * 2; | ||||
|  | ||||
|     boost::transform_iterator_generator<mult_functor, int*>::type i(y, mult_functor(2)); | ||||
|     boost::input_iterator_test(i, x[0], x[1]); | ||||
|     boost::input_iterator_test(boost::make_transform_iterator(&y[0], mult_functor(2)), x[0], x[1]); | ||||
|   } | ||||
|   std::cout << "test successful " << std::endl; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										620
									
								
								type_traits.htm
									
									
									
									
									
								
							
							
						
						
									
										620
									
								
								type_traits.htm
									
									
									
									
									
								
							| @@ -1,620 +0,0 @@ | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" | ||||
| content="text/html; charset=iso-8859-1"> | ||||
| <meta name="Template" | ||||
| content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot"> | ||||
| <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> | ||||
| <title>Type Traits</title> | ||||
| </head> | ||||
|  | ||||
| <body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080"> | ||||
|  | ||||
| <h1><img src="../../c++boost.gif" width="276" height="86">Header | ||||
| <<a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a>></h1> | ||||
|  | ||||
| <p>The contents of <boost/type_traits.hpp> are declared in | ||||
| namespace boost.</p> | ||||
|  | ||||
| <p>The file <<a href="../../boost/detail/type_traits.hpp">boost/type_traits.hpp</a>> | ||||
| contains various template classes that describe the fundamental | ||||
| properties of a type; each class represents a single type | ||||
| property or a single type transformation. This documentation is | ||||
| divided up into the following sections:</p> | ||||
|  | ||||
| <pre><a href="#fop">Fundamental type operations</a> | ||||
| <a href="#fp">Fundamental type properties</a> | ||||
|    <a href="#misc">Miscellaneous</a> | ||||
| <code>   </code><a href="#cv">cv-Qualifiers</a> | ||||
| <code>   </code><a href="#ft">Fundamental Types</a> | ||||
| <code>   </code><a href="#ct">Compound Types</a> | ||||
| <code>   </code><a href="#ot">Object/Scalar Types</a> | ||||
| <a href="#cs">Compiler Support Information</a> | ||||
| <a href="#ec">Example Code</a></pre> | ||||
|  | ||||
| <h2><a name="fop"></a>Fundamental type operations</h2> | ||||
|  | ||||
| <p>Usage: "class_name<T>::type" performs | ||||
| indicated transformation on type T.</p> | ||||
|  | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><p align="center">Expression.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="45%"><p align="center">Description.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="33%"><p align="center">Compiler.</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>remove_volatile<T>::type</code></td> | ||||
|         <td valign="top" width="45%">Creates a type the same as T | ||||
|         but with any top level volatile qualifier removed. For | ||||
|         example "volatile int" would become "int".</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>remove_const<T>::type</code></td> | ||||
|         <td valign="top" width="45%">Creates a type the same as T | ||||
|         but with any top level const qualifier removed. For | ||||
|         example "const int" would become "int".</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>remove_cv<T>::type</code></td> | ||||
|         <td valign="top" width="45%">Creates a type the same as T | ||||
|         but with any top level cv-qualifiers removed. For example | ||||
|         "const int" would become "int", and | ||||
|         "volatile double" would become "double".</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>remove_reference<T>::type</code></td> | ||||
|         <td valign="top" width="45%">If T is a reference type | ||||
|         then removes the reference, otherwise leaves T unchanged. | ||||
|         For example "int&" becomes "int" | ||||
|         but "int*" remains unchanged.</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>add_reference<T>::type</code></td> | ||||
|         <td valign="top" width="45%">If T is a reference type | ||||
|         then leaves T unchanged, otherwise converts T to a | ||||
|         reference type. For example "int&" remains | ||||
|         unchanged, but "double" becomes "double&".</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>remove_bounds<T>::type</code></td> | ||||
|         <td valign="top" width="45%">If T is an array type then | ||||
|         removes the top level array qualifier from T, otherwise | ||||
|         leaves T unchanged. For example "int[2][3]" | ||||
|         becomes "int[3]".</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h2><a name="fp"></a>Fundamental type properties</h2> | ||||
|  | ||||
| <p>Usage: "class_name<T>::value" is true if | ||||
| indicated property is true, false otherwise. (Note that class_name<T>::value | ||||
| is always defined as a compile time constant).</p> | ||||
|  | ||||
| <h3><a name="misc"></a>Miscellaneous</h3> | ||||
|  | ||||
| <table border="1" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td width="37%"><p align="center">Expression</p> | ||||
|         </td> | ||||
|         <td width="36%"><p align="center">Description</p> | ||||
|         </td> | ||||
|         <td width="27%"><p align="center">Compiler</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td width="37%"><div align="center"><center><pre><code>is_same<T,U>::value</code></pre> | ||||
|         </center></div></td> | ||||
|         <td width="36%"><p align="center">True if T and U are the | ||||
|         same type.</p> | ||||
|         </td> | ||||
|         <td width="27%">  </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td width="37%"><div align="center"><center><pre>is_convertible<T,U>::value</pre> | ||||
|         </center></div></td> | ||||
|         <td width="36%"><p align="center">True if type T is | ||||
|         convertible to type U.</p> | ||||
|         </td> | ||||
|         <td width="27%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td width="37%"><div align="center"><center><pre>alignment_of<T>::value</pre> | ||||
|         </center></div></td> | ||||
|         <td width="36%"><p align="center">An integral value | ||||
|         representing the minimum alignment requirements of type T | ||||
|         (strictly speaking defines a multiple of the type's | ||||
|         alignment requirement; for all compilers tested so far | ||||
|         however it does return the actual alignment).</p> | ||||
|         </td> | ||||
|         <td width="27%"> </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h3><a name="cv"></a>cv-Qualifiers</h3> | ||||
|  | ||||
| <p>The following classes determine what cv-qualifiers are present | ||||
| on a type (see 3.93).</p> | ||||
|  | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td valign="top" width="37%"><p align="center">Expression.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="37%"><p align="center">Description.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="27%"><p align="center">Compiler.</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="37%"><code>is_const<T>::value</code></td> | ||||
|         <td valign="top" width="37%">True if type T is top-level | ||||
|         const qualified.</td> | ||||
|         <td valign="top" width="27%">  </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="37%"><code>is_volatile<T>::value</code></td> | ||||
|         <td valign="top" width="37%">True if type T is top-level | ||||
|         volatile qualified.</td> | ||||
|         <td valign="top" width="27%">  </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h3><a name="ft"></a>Fundamental Types</h3> | ||||
|  | ||||
| <p>The following will only ever be true for cv-unqualified types; | ||||
| these are closely based on the section 3.9 of the C++ Standard.</p> | ||||
|  | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><p align="center">Expression.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="45%"><p align="center">Description.</p> | ||||
|         </td> | ||||
|         <td valign="top" width="33%"><p align="center">Compiler.</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_void<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True only if T is void.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_unsigned_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True only if T is one of the | ||||
|         standard unsigned integral types (3.9.1 p3) - unsigned | ||||
|         char, unsigned short, unsigned int, and unsigned long.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_signed_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True only if T is one of the | ||||
|         standard signed integral types (3.9.1 p2) - signed char, | ||||
|         short, int, and long.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a standard | ||||
|         integral type(3.9.1 p7) - T is either char, wchar_t, bool | ||||
|         or either is_standard_signed_integral<T>::value or | ||||
|         is_standard_integral<T>::value is true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_float<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is one of the | ||||
|         standard floating point types(3.9.1 p8) - float, double | ||||
|         or long double.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_arithmetic<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a standard | ||||
|         arithmetic type(3.9.1 p8) - implies is_standard_integral | ||||
|         or is_standard_float is true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_fundamental<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a standard | ||||
|         arithmetic type or if T is void.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_unsigned_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True for compiler specific | ||||
|         unsigned integral types.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_signed_integral<T>>:value</code></td> | ||||
|         <td valign="top" width="45%">True for compiler specific | ||||
|         signed integral types.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_extension_unsigned_integral<T>::value | ||||
|         or is_extension_signed_integral<T>::value is true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_float<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True for compiler specific | ||||
|         floating point types.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_arithmetic<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_extension_integral<T>::value | ||||
|         or is_extension_float<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code> is_extension_fundamental<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_extension_arithmetic<T>::value | ||||
|         or is_void<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code> is_unsigned_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_standard_unsigned_integral<T>::value | ||||
|         or is_extention_unsigned_integral<T>::value are | ||||
|         true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_signed_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_standard_signed_integral<T>::value | ||||
|         or is_extention_signed_integral<T>>::value are | ||||
|         true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_integral<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_standard_integral<T>::value | ||||
|         or is_extention_integral<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_float<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_standard_float<T>::value | ||||
|         or is_extention_float<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_arithmetic<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_integral<T>::value | ||||
|         or is_float<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_fundamental<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if either is_arithmetic<T>::value | ||||
|         or is_void<T>::value are true.</td> | ||||
|         <td valign="top" width="33%"> </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h3><a name="ct"></a>Compound Types</h3> | ||||
|  | ||||
| <p>The following will only ever be true for cv-unqualified types, | ||||
| as defined by the Standard. </p> | ||||
|  | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><p align="center">Expression</p> | ||||
|         </td> | ||||
|         <td valign="top" width="45%"><p align="center">Description</p> | ||||
|         </td> | ||||
|         <td valign="top" width="33%"><p align="center">Compiler</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_array<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is an array type.</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_pointer<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a regular | ||||
|         pointer type - including function pointers - but | ||||
|         excluding pointers to member functions (3.9.2 p1 and 8.3.1).</td> | ||||
|         <td valign="top" width="33%">  </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_member_pointer<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a pointer to a | ||||
|         non-static class member (3.9.2 p1 and 8.3.1).</td> | ||||
|         <td valign="top" width="33%">  </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_reference<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a reference | ||||
|         type (3.9.2 p1 and 8.3.2).</td> | ||||
|         <td valign="top" width="33%">  </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_class<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a class or | ||||
|         struct type.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_union<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a union type.</td> | ||||
|         <td valign="top" width="33%"><p align="center">C</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_enum<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is an enumerator | ||||
|         type.</td> | ||||
|         <td valign="top" width="33%"><p align="center">C</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_compound<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is any of the | ||||
|         above compound types.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h3><a name="ot"></a>Object/Scalar Types</h3> | ||||
|  | ||||
| <p>The following ignore any top level cv-qualifiers: if <code>class_name<T>::value</code> | ||||
| is true then <code>class_name<cv-qualified-T>::value</code> | ||||
| will also be true.</p> | ||||
|  | ||||
| <table border="1" cellpadding="7" cellspacing="1" width="100%"> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><p align="center">Expression</p> | ||||
|         </td> | ||||
|         <td valign="top" width="45%"><p align="center">Description</p> | ||||
|         </td> | ||||
|         <td valign="top" width="33%"><p align="center">Compiler</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_object<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is not a reference | ||||
|         type, or a (possibly cv-qualified) void type.</td> | ||||
|         <td valign="top" width="33%"><p align="center">P</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_standard_scalar<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a standard | ||||
|         arithmetic type, an enumerated type, a pointer or a | ||||
|         member pointer.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_extension_scalar<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is an extentions | ||||
|         arithmetic type, an enumerated type, a pointer or a | ||||
|         member pointer.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_scalar<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is an arithmetic | ||||
|         type, an enumerated type, a pointer or a member pointer.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_POD<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is a "Plain | ||||
|         Old Data" type (see 3.9 p2&p3). Note that | ||||
|         although this requires compiler support to be correct in | ||||
|         all cases, if T is a scalar or an array of scalars then | ||||
|         we can correctly define T as a POD.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PC</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>is_empty<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T is an empty struct | ||||
|         or class. If the compiler implements the "zero sized | ||||
|         empty base classes" optimisation, then is_empty will | ||||
|         correctly guess whether T is empty. Relies upon is_class | ||||
|         to determine whether T is a class type. Screens out enum | ||||
|         types by using is_convertible<T,int>, this means | ||||
|         that empty classes that overload operator int(), will not | ||||
|         be classified as empty.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PCD</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>has_trivial_constructor<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T has a trivial | ||||
|         default constructor - that is T() is equivalent to memset.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PC</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>has_trivial_copy<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T has a trivial copy | ||||
|         constructor - that is T(const T&) is equivalent to | ||||
|         memcpy.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PC</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>has_trivial_assign<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T has a trivial | ||||
|         assignment operator - that is if T::operator=(const T&) | ||||
|         is equivalent to memcpy.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PC</p> | ||||
|         </td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="45%"><code>has_trivial_destructor<T>::value</code></td> | ||||
|         <td valign="top" width="45%">True if T has a trivial | ||||
|         destructor - that is if T::~T() has no effect.</td> | ||||
|         <td valign="top" width="33%"><p align="center">PC</p> | ||||
|         </td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <h2><a name="cs"></a>Compiler Support Information</h2> | ||||
|  | ||||
| <p>The legends used in the tables above have the following | ||||
| meanings:</p> | ||||
|  | ||||
| <table border="0" cellpadding="7" cellspacing="0" width="480"> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><p align="center">P</p> | ||||
|         </td> | ||||
|         <td valign="top" width="90%">Denotes that the class | ||||
|         requires support for partial specialisation of class | ||||
|         templates to work correctly.</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><p align="center">C</p> | ||||
|         </td> | ||||
|         <td valign="top" width="90%">Denotes that direct compiler | ||||
|         support for that traits class is required.</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><p align="center">D</p> | ||||
|         </td> | ||||
|         <td valign="top" width="90%">Denotes that the traits | ||||
|         class is dependent upon a class that requires direct | ||||
|         compiler support.</td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <p>For those classes that are marked with a D or C, if compiler | ||||
| support is not provided, this type trait may return "false" | ||||
| when the correct value is actually "true". The single | ||||
| exception to this rule is "is_class", which attempts to | ||||
| guess whether or not T is really a class, and may return "true" | ||||
| when the correct value is actually "false". This can | ||||
| happen if: T is a union, T is an enum, or T is a compiler-supplied | ||||
| scalar type that is not specialised for in these type traits.</p> | ||||
|  | ||||
| <p><i>If there is no compiler support</i>, to ensure that these | ||||
| traits <i>always</i> return the correct values, specialise 'is_enum' | ||||
| for each user-defined enumeration type, 'is_union' for each user-defined | ||||
| union type, 'is_empty' for each user-defined empty composite type, | ||||
| and 'is_POD' for each user-defined POD type. The 'has_*' traits | ||||
| should also be specialized if the user-defined type has those | ||||
| traits and is <i>not</i> a POD.</p> | ||||
|  | ||||
| <p>The following rules are automatically enforced:</p> | ||||
|  | ||||
| <p>is_enum implies is_POD</p> | ||||
|  | ||||
| <p>is_POD implies has_*</p> | ||||
|  | ||||
| <p>This means, for example, if you have an empty POD-struct, just | ||||
| specialize is_empty and is_POD, which will cause all the has_* to | ||||
| also return true.</p> | ||||
|  | ||||
| <h2><a name="ec"></a>Example code</h2> | ||||
|  | ||||
| <p>Type-traits comes with two sample programs: <a | ||||
| href="type_traits_test.cpp">type_traits_test.cpp</a> tests the | ||||
| type traits classes - mostly this is a test of your compiler's | ||||
| support for the concepts used in the type traits implementation, | ||||
| while <a href="algo_opt_examples.cpp">algo_opt_examples.cpp</a> | ||||
| uses the type traits classes to "optimise" some | ||||
| familiar standard library algorithms.</p> | ||||
|  | ||||
| <p>There are four algorithm examples in algo_opt_examples.cpp:</p> | ||||
|  | ||||
| <table border="0" cellpadding="7" cellspacing="0" width="638"> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><pre>opt::copy</pre> | ||||
|         </td> | ||||
|         <td valign="top" width="50%">If the copy operation can be | ||||
|         performed using memcpy then does so, otherwise uses a | ||||
|         regular element by element copy (<i>c.f.</i> std::copy).</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><pre>opt::fill</pre> | ||||
|         </td> | ||||
|         <td valign="top" width="50%">If the fill operation can be | ||||
|         performed by memset, then does so, otherwise uses a | ||||
|         regular element by element assign. Also uses call_traits | ||||
|         to optimise how the parameters can be passed (<i>c.f.</i> | ||||
|         std::fill).</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><pre>opt::destroy_array</pre> | ||||
|         </td> | ||||
|         <td valign="top" width="50%">If the type in the array has | ||||
|         a trivial destructor then does nothing, otherwise calls | ||||
|         destructors for all elements in the array - this | ||||
|         algorithm is the reverse of std::uninitialized_copy / std::uninitialized_fill.</td> | ||||
|     </tr> | ||||
|     <tr> | ||||
|         <td valign="top" width="50%"><pre>opt::iter_swap</pre> | ||||
|         </td> | ||||
|         <td valign="top" width="50%">Determines whether the | ||||
|         iterator is a proxy-iterator: if it is then does a "slow | ||||
|         and safe" swap, otherwise calls std::swap on the | ||||
|         assumption that std::swap may be specialised for the | ||||
|         iterated type.</td> | ||||
|     </tr> | ||||
| </table> | ||||
|  | ||||
| <p> </p> | ||||
|  | ||||
| <hr> | ||||
|  | ||||
| <p>Revised 01 September 2000</p> | ||||
|  | ||||
| <p><EFBFBD> Copyright boost.org 2000. Permission to copy, use, modify, | ||||
| sell and distribute this document is granted provided this | ||||
| copyright notice appears in all copies. This document is provided | ||||
| "as is" without express or implied warranty, and with | ||||
| no claim as to its suitability for any purpose.</p> | ||||
|  | ||||
| <p>Based on contributions by Steve Cleary, Beman Dawes, Howard | ||||
| Hinnant and John Maddock.</p> | ||||
|  | ||||
| <p>Maintained by <a href="mailto:John_Maddock@compuserve.com">John | ||||
| Maddock</a>, the latest version of this file can be found at <a | ||||
| href="http://www.boost.org/">www.boost.org</a>, and the boost | ||||
| discussion list at <a href="http://www.egroups.com/list/boost">www.egroups.com/list/boost</a>.</p> | ||||
| </body> | ||||
| </html> | ||||
| @@ -1,644 +0,0 @@ | ||||
| //  (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000. | ||||
| //  Permission to copy, use, modify, sell and | ||||
| //  distribute this software is granted provided this copyright notice appears | ||||
| //  in all copies. This software is provided "as is" without express or implied | ||||
| //  warranty, and with no claim as to its suitability for any purpose. | ||||
|  | ||||
| // standalone test program for <boost/type_traits.hpp> | ||||
|  | ||||
| /* Release notes: | ||||
|    31st July 2000: | ||||
|       Added extra tests for is_empty, is_convertible, alignment_of. | ||||
|    23rd July 2000: | ||||
|       Removed all call_traits tests to call_traits_test.cpp | ||||
|       Removed all compressed_pair tests to compressed_pair_tests.cpp | ||||
|       Improved tests macros | ||||
|       Tidied up specialistions of type_types classes for test cases. | ||||
| */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <typeinfo> | ||||
|  | ||||
| #include <boost/type_traits.hpp> | ||||
| #include <boost/utility.hpp> | ||||
| #include "type_traits_test.hpp" | ||||
|  | ||||
| using namespace boost; | ||||
|  | ||||
| // Since there is no compiler support, we should specialize: | ||||
| //  is_enum for all enumerations (is_enum implies is_POD) | ||||
| //  is_union for all unions | ||||
| //  is_empty for all empty composites | ||||
| //  is_POD for all PODs (except enums) (is_POD implies has_*) | ||||
| //  has_* for any UDT that has that trait and is not POD | ||||
|  | ||||
| enum enum_UDT{ one, two, three }; | ||||
| struct UDT | ||||
| { | ||||
|    UDT(); | ||||
|    ~UDT(); | ||||
|    UDT(const UDT&); | ||||
|    UDT& operator=(const UDT&); | ||||
|    int i; | ||||
|  | ||||
|    void f1(); | ||||
|    int f2(); | ||||
|    int f3(int); | ||||
|    int f4(int, float); | ||||
| }; | ||||
|  | ||||
| struct POD_UDT { int x; }; | ||||
| struct empty_UDT{ ~empty_UDT(){}; }; | ||||
| struct empty_POD_UDT{}; | ||||
| union union_UDT | ||||
| { | ||||
|   int x; | ||||
|   double y; | ||||
|   ~union_UDT(); | ||||
| }; | ||||
| union POD_union_UDT | ||||
| { | ||||
|   int x; | ||||
|   double y; | ||||
| }; | ||||
| union empty_union_UDT | ||||
| { | ||||
|   ~empty_union_UDT(); | ||||
| }; | ||||
| union empty_POD_union_UDT{}; | ||||
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION | ||||
| namespace boost { | ||||
| template <> struct is_enum<enum_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_POD<POD_UDT> | ||||
| { static const bool value = true; }; | ||||
| // this type is not POD, so we have to specialize the has_* individually | ||||
| template <> struct has_trivial_constructor<empty_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct has_trivial_copy<empty_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct has_trivial_assign<empty_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_POD<empty_POD_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_union<union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_union<POD_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_POD<POD_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_union<empty_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| // this type is not POD, so we have to specialize the has_* individually | ||||
| template <> struct has_trivial_constructor<empty_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct has_trivial_copy<empty_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct has_trivial_assign<empty_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_union<empty_POD_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| template <> struct is_POD<empty_POD_union_UDT> | ||||
| { static const bool value = true; }; | ||||
| } | ||||
| #else | ||||
| namespace boost { | ||||
| template <> struct is_enum<enum_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_POD<POD_UDT> | ||||
| { enum{ value = true }; }; | ||||
| // this type is not POD, so we have to specialize the has_* individually | ||||
| template <> struct has_trivial_constructor<empty_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct has_trivial_copy<empty_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct has_trivial_assign<empty_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_POD<empty_POD_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_union<union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_union<POD_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_POD<POD_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_union<empty_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| // this type is not POD, so we have to specialize the has_* individually | ||||
| template <> struct has_trivial_constructor<empty_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct has_trivial_copy<empty_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct has_trivial_assign<empty_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_union<empty_POD_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| template <> struct is_POD<empty_POD_union_UDT> | ||||
| { enum{ value = true }; }; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| class Base { }; | ||||
|  | ||||
| class Deriverd : public Base { }; | ||||
|  | ||||
| class NonDerived { }; | ||||
|  | ||||
| enum enum1 | ||||
| { | ||||
|    one_,two_ | ||||
| }; | ||||
|  | ||||
| enum enum2 | ||||
| { | ||||
|    three_,four_ | ||||
| }; | ||||
|  | ||||
| struct VB | ||||
| { | ||||
|    virtual ~VB(){}; | ||||
| }; | ||||
|  | ||||
| struct VD : VB | ||||
| { | ||||
|    ~VD(){}; | ||||
| }; | ||||
| // | ||||
| // struct non_pointer: | ||||
| // used to verify that is_pointer does not return | ||||
| // true for class types that implement operator void*() | ||||
| // | ||||
| struct non_pointer | ||||
| { | ||||
|    operator void*(){return this;} | ||||
| }; | ||||
| // | ||||
| // struct non_empty: | ||||
| // used to verify that is_empty does not emit | ||||
| // spurious warnings or errors. | ||||
| // | ||||
| struct non_empty : boost::noncopyable | ||||
| { | ||||
|    int i; | ||||
| }; | ||||
|  | ||||
| // Steve: All comments that I (Steve Cleary) have added below are prefixed with | ||||
| //  "Steve:"  The failures that BCB4 has on the tests are due to Borland's | ||||
| //  not considering cv-qual's as a part of the type -- they are considered | ||||
| //  compiler hints only.  These failures should be fixed before long. | ||||
|  | ||||
| int main() | ||||
| { | ||||
|    std::cout << "Checking type operations..." << std::endl << std::endl; | ||||
|  | ||||
|    // cv-qualifiers applied to reference types should have no effect | ||||
|    // declare these here for later use with is_reference and remove_reference: | ||||
|    typedef int& r_type; | ||||
|    typedef const r_type cr_type; | ||||
|  | ||||
|    type_test(int, remove_reference<int>::type) | ||||
|    type_test(const int, remove_reference<const int>::type) | ||||
|    type_test(int, remove_reference<int&>::type) | ||||
|    type_test(const int, remove_reference<const int&>::type) | ||||
|    type_test(volatile int, remove_reference<volatile int&>::type) | ||||
|    type_test(int, remove_reference<cr_type>::type) | ||||
|  | ||||
|    type_test(int, remove_const<const int>::type) | ||||
|    // Steve: fails on BCB4 | ||||
|    type_test(volatile int, remove_const<volatile int>::type) | ||||
|    // Steve: fails on BCB4 | ||||
|    type_test(volatile int, remove_const<const volatile int>::type) | ||||
|    type_test(int, remove_const<int>::type) | ||||
|    type_test(int*, remove_const<int* const>::type) | ||||
|    type_test(int, remove_volatile<volatile int>::type) | ||||
|    // Steve: fails on BCB4 | ||||
|    type_test(const int, remove_volatile<const int>::type) | ||||
|    // Steve: fails on BCB4 | ||||
|    type_test(const int, remove_volatile<const volatile int>::type) | ||||
|    type_test(int, remove_volatile<int>::type) | ||||
|    type_test(int*, remove_volatile<int* volatile>::type) | ||||
|    type_test(int, remove_cv<volatile int>::type) | ||||
|    type_test(int, remove_cv<const int>::type) | ||||
|    type_test(int, remove_cv<const volatile int>::type) | ||||
|    type_test(int, remove_cv<int>::type) | ||||
|    type_test(int*, remove_cv<int* volatile>::type) | ||||
|    type_test(int*, remove_cv<int* const>::type) | ||||
|    type_test(int*, remove_cv<int* const volatile>::type) | ||||
|    type_test(const int *, remove_cv<const int * const>::type) | ||||
|    type_test(int, remove_bounds<int>::type) | ||||
|    type_test(int*, remove_bounds<int*>::type) | ||||
|    type_test(int, remove_bounds<int[3]>::type) | ||||
|    type_test(int[3], remove_bounds<int[2][3]>::type) | ||||
|  | ||||
|    std::cout << std::endl << "Checking type properties..." << std::endl << std::endl; | ||||
|  | ||||
|    value_test(true, (is_same<int, int>::value)) | ||||
|    value_test(false, (is_same<int, const int>::value)) | ||||
|    value_test(false, (is_same<int, int&>::value)) | ||||
|    value_test(false, (is_same<int*, const int*>::value)) | ||||
|    value_test(false, (is_same<int*, int*const>::value)) | ||||
|    value_test(false, (is_same<int, int[2]>::value)) | ||||
|    value_test(false, (is_same<int*, int[2]>::value)) | ||||
|    value_test(false, (is_same<int[4], int[2]>::value)) | ||||
|  | ||||
|    value_test(false, is_const<int>::value) | ||||
|    value_test(true, is_const<const int>::value) | ||||
|    value_test(false, is_const<volatile int>::value) | ||||
|    value_test(true, is_const<const volatile int>::value) | ||||
|  | ||||
|    value_test(false, is_volatile<int>::value) | ||||
|    value_test(false, is_volatile<const int>::value) | ||||
|    value_test(true, is_volatile<volatile int>::value) | ||||
|    value_test(true, is_volatile<const volatile int>::value) | ||||
|  | ||||
|    value_test(true, is_void<void>::value) | ||||
|    // Steve: fails on BCB4 | ||||
|    // JM: but looks as though it should according to [3.9.3p1]? | ||||
|    //value_test(false, is_void<const void>::value) | ||||
|    value_test(false, is_void<int>::value) | ||||
|  | ||||
|    value_test(false, is_standard_unsigned_integral<UDT>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<void>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<bool>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<char>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<signed char>::value) | ||||
|    value_test(true, is_standard_unsigned_integral<unsigned char>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<wchar_t>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<short>::value) | ||||
|    value_test(true, is_standard_unsigned_integral<unsigned short>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<int>::value) | ||||
|    value_test(true, is_standard_unsigned_integral<unsigned int>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<long>::value) | ||||
|    value_test(true, is_standard_unsigned_integral<unsigned long>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<float>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<double>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<long double>::value) | ||||
|    #ifdef ULLONG_MAX | ||||
|    value_test(false, is_standard_unsigned_integral<long long>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<unsigned long long>::value) | ||||
|    #endif | ||||
|    #if defined(__BORLANDC__) || defined(_MSC_VER) | ||||
|    value_test(false, is_standard_unsigned_integral<__int64>::value) | ||||
|    value_test(false, is_standard_unsigned_integral<unsigned __int64>::value) | ||||
|    #endif | ||||
|  | ||||
|    value_test(false, is_standard_signed_integral<UDT>::value) | ||||
|    value_test(false, is_standard_signed_integral<void>::value) | ||||
|    value_test(false, is_standard_signed_integral<bool>::value) | ||||
|    value_test(false, is_standard_signed_integral<char>::value) | ||||
|    value_test(true, is_standard_signed_integral<signed char>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned char>::value) | ||||
|    value_test(false, is_standard_signed_integral<wchar_t>::value) | ||||
|    value_test(true, is_standard_signed_integral<short>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned short>::value) | ||||
|    value_test(true, is_standard_signed_integral<int>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned int>::value) | ||||
|    value_test(true, is_standard_signed_integral<long>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned long>::value) | ||||
|    value_test(false, is_standard_signed_integral<float>::value) | ||||
|    value_test(false, is_standard_signed_integral<double>::value) | ||||
|    value_test(false, is_standard_signed_integral<long double>::value) | ||||
|    #ifdef ULLONG_MAX | ||||
|    value_test(false, is_standard_signed_integral<long long>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned long long>::value) | ||||
|    #endif | ||||
|    #if defined(__BORLANDC__) || defined(_MSC_VER) | ||||
|    value_test(false, is_standard_signed_integral<__int64>::value) | ||||
|    value_test(false, is_standard_signed_integral<unsigned __int64>::value) | ||||
|    #endif | ||||
|  | ||||
|    value_test(false, is_standard_arithmetic<UDT>::value) | ||||
|    value_test(false, is_standard_arithmetic<void>::value) | ||||
|    value_test(true, is_standard_arithmetic<bool>::value) | ||||
|    value_test(true, is_standard_arithmetic<char>::value) | ||||
|    value_test(true, is_standard_arithmetic<signed char>::value) | ||||
|    value_test(true, is_standard_arithmetic<unsigned char>::value) | ||||
|    value_test(true, is_standard_arithmetic<wchar_t>::value) | ||||
|    value_test(true, is_standard_arithmetic<short>::value) | ||||
|    value_test(true, is_standard_arithmetic<unsigned short>::value) | ||||
|    value_test(true, is_standard_arithmetic<int>::value) | ||||
|    value_test(true, is_standard_arithmetic<unsigned int>::value) | ||||
|    value_test(true, is_standard_arithmetic<long>::value) | ||||
|    value_test(true, is_standard_arithmetic<unsigned long>::value) | ||||
|    value_test(true, is_standard_arithmetic<float>::value) | ||||
|    value_test(true, is_standard_arithmetic<double>::value) | ||||
|    value_test(true, is_standard_arithmetic<long double>::value) | ||||
|    #ifdef ULLONG_MAX | ||||
|    value_test(false, is_standard_arithmetic<long long>::value) | ||||
|    value_test(false, is_standard_arithmetic<unsigned long long>::value) | ||||
|    #endif | ||||
|    #if defined(__BORLANDC__) || defined(_MSC_VER) | ||||
|    value_test(false, is_standard_arithmetic<__int64>::value) | ||||
|    value_test(false, is_standard_arithmetic<unsigned __int64>::value) | ||||
|    #endif | ||||
|  | ||||
|    value_test(false, is_standard_fundamental<UDT>::value) | ||||
|    value_test(true, is_standard_fundamental<void>::value) | ||||
|    value_test(true, is_standard_fundamental<bool>::value) | ||||
|    value_test(true, is_standard_fundamental<char>::value) | ||||
|    value_test(true, is_standard_fundamental<signed char>::value) | ||||
|    value_test(true, is_standard_fundamental<unsigned char>::value) | ||||
|    value_test(true, is_standard_fundamental<wchar_t>::value) | ||||
|    value_test(true, is_standard_fundamental<short>::value) | ||||
|    value_test(true, is_standard_fundamental<unsigned short>::value) | ||||
|    value_test(true, is_standard_fundamental<int>::value) | ||||
|    value_test(true, is_standard_fundamental<unsigned int>::value) | ||||
|    value_test(true, is_standard_fundamental<long>::value) | ||||
|    value_test(true, is_standard_fundamental<unsigned long>::value) | ||||
|    value_test(true, is_standard_fundamental<float>::value) | ||||
|    value_test(true, is_standard_fundamental<double>::value) | ||||
|    value_test(true, is_standard_fundamental<long double>::value) | ||||
|    #ifdef ULLONG_MAX | ||||
|    value_test(false, is_standard_fundamental<long long>::value) | ||||
|    value_test(false, is_standard_fundamental<unsigned long long>::value) | ||||
|    #endif | ||||
|    #if defined(__BORLANDC__) || defined(_MSC_VER) | ||||
|    value_test(false, is_standard_fundamental<__int64>::value) | ||||
|    value_test(false, is_standard_fundamental<unsigned __int64>::value) | ||||
|    #endif | ||||
|  | ||||
|    value_test(false, is_arithmetic<UDT>::value) | ||||
|    value_test(true, is_arithmetic<char>::value) | ||||
|    value_test(true, is_arithmetic<signed char>::value) | ||||
|    value_test(true, is_arithmetic<unsigned char>::value) | ||||
|    value_test(true, is_arithmetic<wchar_t>::value) | ||||
|    value_test(true, is_arithmetic<short>::value) | ||||
|    value_test(true, is_arithmetic<unsigned short>::value) | ||||
|    value_test(true, is_arithmetic<int>::value) | ||||
|    value_test(true, is_arithmetic<unsigned int>::value) | ||||
|    value_test(true, is_arithmetic<long>::value) | ||||
|    value_test(true, is_arithmetic<unsigned long>::value) | ||||
|    value_test(true, is_arithmetic<float>::value) | ||||
|    value_test(true, is_arithmetic<double>::value) | ||||
|    value_test(true, is_arithmetic<long double>::value) | ||||
|    value_test(true, is_arithmetic<bool>::value) | ||||
|    #ifdef ULLONG_MAX | ||||
|    value_test(true, is_arithmetic<long long>::value) | ||||
|    value_test(true, is_arithmetic<unsigned long long>::value) | ||||
|    #endif | ||||
|    #if defined(__BORLANDC__) || defined(_MSC_VER) | ||||
|    value_test(true, is_arithmetic<__int64>::value) | ||||
|    value_test(true, is_arithmetic<unsigned __int64>::value) | ||||
|    #endif | ||||
|  | ||||
|    value_test(false, is_array<int>::value) | ||||
|    value_test(false, is_array<int*>::value) | ||||
|    value_test(false, is_array<const int*>::value) | ||||
|    value_test(false, is_array<const volatile int*>::value) | ||||
|    value_test(true, is_array<int[2]>::value) | ||||
|    value_test(true, is_array<const int[2]>::value) | ||||
|    value_test(true, is_array<const volatile int[2]>::value) | ||||
|    value_test(true, is_array<int[2][3]>::value) | ||||
|    value_test(true, is_array<UDT[2]>::value) | ||||
|    value_test(false, is_array<int(&)[2]>::value) | ||||
|  | ||||
|    typedef void(*f1)(); | ||||
|    typedef int(*f2)(int); | ||||
|    typedef int(*f3)(int, bool); | ||||
|    typedef void (UDT::*mf1)(); | ||||
|    typedef int (UDT::*mf2)(); | ||||
|    typedef int (UDT::*mf3)(int); | ||||
|    typedef int (UDT::*mf4)(int, float); | ||||
|     | ||||
|    value_test(false, is_const<f1>::value) | ||||
|    value_test(false, is_reference<f1>::value) | ||||
|    value_test(false, is_array<f1>::value) | ||||
|    value_test(false, is_pointer<int>::value) | ||||
|    value_test(false, is_pointer<int&>::value) | ||||
|    value_test(true, is_pointer<int*>::value) | ||||
|    value_test(true, is_pointer<const int*>::value) | ||||
|    value_test(true, is_pointer<volatile int*>::value) | ||||
|    value_test(true, is_pointer<non_pointer*>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 | ||||
|    value_test(false, is_pointer<int*const>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 | ||||
|    value_test(false, is_pointer<int*volatile>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 | ||||
|    value_test(false, is_pointer<int*const volatile>::value) | ||||
|    // JM 02 Oct 2000: | ||||
|    value_test(false, is_pointer<non_pointer>::value) | ||||
|    value_test(false, is_pointer<int*&>::value) | ||||
|    value_test(false, is_pointer<int(&)[2]>::value) | ||||
|    value_test(false, is_pointer<int[2]>::value) | ||||
|    value_test(false, is_pointer<char[sizeof(void*)]>::value) | ||||
|  | ||||
|    value_test(true, is_pointer<f1>::value) | ||||
|    value_test(true, is_pointer<f2>::value) | ||||
|    value_test(true, is_pointer<f3>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3 | ||||
|    value_test(false, is_pointer<mf1>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3 | ||||
|    value_test(false, is_pointer<mf2>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3 | ||||
|    value_test(false, is_pointer<mf3>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9.2p3 | ||||
|    value_test(false, is_pointer<mf4>::value) | ||||
|  | ||||
|    value_test(false, is_reference<bool>::value) | ||||
|    value_test(true, is_reference<int&>::value) | ||||
|    value_test(true, is_reference<const int&>::value) | ||||
|    value_test(true, is_reference<volatile int &>::value) | ||||
|    value_test(true, is_reference<r_type>::value) | ||||
|    value_test(true, is_reference<cr_type>::value) | ||||
|    value_test(true, is_reference<const UDT&>::value) | ||||
|  | ||||
|    value_test(false, is_class<int>::value) | ||||
|    value_test(false, is_class<const int>::value) | ||||
|    value_test(false, is_class<volatile int>::value) | ||||
|    value_test(false, is_class<int*>::value) | ||||
|    value_test(false, is_class<int* const>::value) | ||||
|    value_test(false, is_class<int[2]>::value) | ||||
|    value_test(false, is_class<int&>::value) | ||||
|    value_test(false, is_class<mf4>::value) | ||||
|    value_test(false, is_class<f1>::value) | ||||
|    value_test(false, is_class<enum_UDT>::value) | ||||
|    value_test(true, is_class<UDT>::value) | ||||
|    value_test(true, is_class<UDT const>::value) | ||||
|    value_test(true, is_class<UDT volatile>::value) | ||||
|    value_test(true, is_class<empty_UDT>::value) | ||||
|    value_test(true, is_class<std::iostream>::value) | ||||
|    value_test(false, is_class<UDT*>::value) | ||||
|    value_test(false, is_class<UDT[2]>::value) | ||||
|    value_test(false, is_class<UDT&>::value) | ||||
|  | ||||
|    value_test(true, is_object<int>::value) | ||||
|    value_test(true, is_object<UDT>::value) | ||||
|    value_test(false, is_object<int&>::value) | ||||
|    value_test(false, is_object<void>::value) | ||||
|    value_test(true, is_standard_scalar<int>::value) | ||||
|    value_test(true, is_extension_scalar<void*>::value) | ||||
|  | ||||
|    value_test(false, is_enum<int>::value) | ||||
|    value_test(true, is_enum<enum_UDT>::value) | ||||
|  | ||||
|    value_test(false, is_member_pointer<f1>::value) | ||||
|    value_test(false, is_member_pointer<f2>::value) | ||||
|    value_test(false, is_member_pointer<f3>::value) | ||||
|    value_test(true, is_member_pointer<mf1>::value) | ||||
|    value_test(true, is_member_pointer<mf2>::value) | ||||
|    value_test(true, is_member_pointer<mf3>::value) | ||||
|    value_test(true, is_member_pointer<mf4>::value) | ||||
|  | ||||
|    value_test(false, is_empty<int>::value) | ||||
|    value_test(false, is_empty<int*>::value) | ||||
|    value_test(false, is_empty<int&>::value) | ||||
| #if defined(__MWERKS__) || defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
|    // apparent compiler bug causes this to fail to compile: | ||||
|    value_fail(false, is_empty<int[2]>::value) | ||||
| #else | ||||
|    value_test(false, is_empty<int[2]>::value) | ||||
| #endif | ||||
| #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
|    value_fail(false, is_empty<f1>::value) | ||||
| #else | ||||
|    value_test(false, is_empty<f1>::value) | ||||
| #endif | ||||
|    value_test(false, is_empty<mf1>::value) | ||||
|    value_test(false, is_empty<UDT>::value) | ||||
|    value_test(true, is_empty<empty_UDT>::value) | ||||
|    value_test(true, is_empty<empty_POD_UDT>::value) | ||||
| #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
|    value_fail(true, is_empty<empty_union_UDT>::value) | ||||
| #else | ||||
|    value_test(true, is_empty<empty_union_UDT>::value) | ||||
| #endif | ||||
|    value_test(false, is_empty<enum_UDT>::value) | ||||
|    value_test(true, is_empty<boost::noncopyable>::value) | ||||
|    value_test(false, is_empty<non_empty>::value) | ||||
|  | ||||
|    value_test(true, has_trivial_constructor<int>::value) | ||||
|    value_test(true, has_trivial_constructor<int*>::value) | ||||
|    value_test(true, has_trivial_constructor<int*const>::value) | ||||
|    value_test(true, has_trivial_constructor<const int>::value) | ||||
|    value_test(true, has_trivial_constructor<volatile int>::value) | ||||
|    value_test(true, has_trivial_constructor<int[2]>::value) | ||||
|    value_test(true, has_trivial_constructor<int[3][2]>::value) | ||||
|    value_test(true, has_trivial_constructor<int[2][4][5][6][3]>::value) | ||||
|    value_test(true, has_trivial_constructor<f1>::value) | ||||
|    value_test(true, has_trivial_constructor<mf2>::value) | ||||
|    value_test(false, has_trivial_constructor<UDT>::value) | ||||
|    value_test(true, has_trivial_constructor<empty_UDT>::value) | ||||
|    value_test(true, has_trivial_constructor<enum_UDT>::value) | ||||
|  | ||||
|    value_test(true, has_trivial_copy<int>::value) | ||||
|    value_test(true, has_trivial_copy<int*>::value) | ||||
|    value_test(true, has_trivial_copy<int*const>::value) | ||||
|    value_test(true, has_trivial_copy<const int>::value) | ||||
|    // Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10 | ||||
|    value_test(true, has_trivial_copy<volatile int>::value) | ||||
|    value_test(true, has_trivial_copy<int[2]>::value) | ||||
|    value_test(true, has_trivial_copy<int[3][2]>::value) | ||||
|    value_test(true, has_trivial_copy<int[2][4][5][6][3]>::value) | ||||
|    value_test(true, has_trivial_copy<f1>::value) | ||||
|    value_test(true, has_trivial_copy<mf2>::value) | ||||
|    value_test(false, has_trivial_copy<UDT>::value) | ||||
|    value_test(true, has_trivial_copy<empty_UDT>::value) | ||||
|    value_test(true, has_trivial_copy<enum_UDT>::value) | ||||
|  | ||||
|    value_test(true, has_trivial_assign<int>::value) | ||||
|    value_test(true, has_trivial_assign<int*>::value) | ||||
|    value_test(true, has_trivial_assign<int*const>::value) | ||||
|    value_test(true, has_trivial_assign<const int>::value) | ||||
|    // Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10 | ||||
|    value_test(true, has_trivial_assign<volatile int>::value) | ||||
|    value_test(true, has_trivial_assign<int[2]>::value) | ||||
|    value_test(true, has_trivial_assign<int[3][2]>::value) | ||||
|    value_test(true, has_trivial_assign<int[2][4][5][6][3]>::value) | ||||
|    value_test(true, has_trivial_assign<f1>::value) | ||||
|    value_test(true, has_trivial_assign<mf2>::value) | ||||
|    value_test(false, has_trivial_assign<UDT>::value) | ||||
|    value_test(true, has_trivial_assign<empty_UDT>::value) | ||||
|    value_test(true, has_trivial_assign<enum_UDT>::value) | ||||
|  | ||||
|    value_test(true, has_trivial_destructor<int>::value) | ||||
|    value_test(true, has_trivial_destructor<int*>::value) | ||||
|    value_test(true, has_trivial_destructor<int*const>::value) | ||||
|    value_test(true, has_trivial_destructor<const int>::value) | ||||
|    value_test(true, has_trivial_destructor<volatile int>::value) | ||||
|    value_test(true, has_trivial_destructor<int[2]>::value) | ||||
|    value_test(true, has_trivial_destructor<int[3][2]>::value) | ||||
|    value_test(true, has_trivial_destructor<int[2][4][5][6][3]>::value) | ||||
|    value_test(true, has_trivial_destructor<f1>::value) | ||||
|    value_test(true, has_trivial_destructor<mf2>::value) | ||||
|    value_test(false, has_trivial_destructor<UDT>::value) | ||||
|    value_test(false, has_trivial_destructor<empty_UDT>::value) | ||||
|    value_test(true, has_trivial_destructor<enum_UDT>::value) | ||||
|  | ||||
|    value_test(true, is_POD<int>::value) | ||||
|    value_test(true, is_POD<int*>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9p10 | ||||
|    value_test(false, is_POD<int&>::value) | ||||
|    value_test(true, is_POD<int*const>::value) | ||||
|    value_test(true, is_POD<const int>::value) | ||||
|    // Steve: was 'false', should be 'true', via 3.9p10 | ||||
|    value_test(true, is_POD<volatile int>::value) | ||||
|    // Steve: was 'true', should be 'false', via 3.9p10 | ||||
|    value_test(false, is_POD<const int&>::value) | ||||
|    value_test(true, is_POD<int[2]>::value) | ||||
|    value_test(true, is_POD<int[3][2]>::value) | ||||
|    value_test(true, is_POD<int[2][4][5][6][3]>::value) | ||||
|    value_test(true, is_POD<f1>::value) | ||||
|    value_test(true, is_POD<mf2>::value) | ||||
|    value_test(false, is_POD<UDT>::value) | ||||
|    value_test(false, is_POD<empty_UDT>::value) | ||||
|    value_test(true, is_POD<enum_UDT>::value) | ||||
|  | ||||
|    value_test(true, (boost::is_convertible<Deriverd,Base>::value)); | ||||
|    value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value)); | ||||
|    value_test(true, (boost::is_convertible<Base,Base>::value)); | ||||
|    value_test(false, (boost::is_convertible<Base,Deriverd>::value)); | ||||
|    value_test(true, (boost::is_convertible<Deriverd,Deriverd>::value)); | ||||
|    value_test(false, (boost::is_convertible<NonDerived,Base>::value)); | ||||
|    value_test(false, (boost::is_convertible<boost::noncopyable, int>::value)); | ||||
|    value_test(true, (boost::is_convertible<float,int>::value)); | ||||
| #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | ||||
|    value_test(false, (boost::is_convertible<float,void>::value)); | ||||
|    value_test(false, (boost::is_convertible<void,float>::value)); | ||||
|    value_test(true, (boost::is_convertible<void,void>::value)); | ||||
| #endif | ||||
|    value_test(true, (boost::is_convertible<enum1, int>::value)); | ||||
|    value_test(true, (boost::is_convertible<Deriverd*, Base*>::value)); | ||||
|    value_test(false, (boost::is_convertible<Base*, Deriverd*>::value)); | ||||
|    value_test(true, (boost::is_convertible<Deriverd&, Base&>::value)); | ||||
|    value_test(false, (boost::is_convertible<Base&, Deriverd&>::value)); | ||||
|    value_test(true, (boost::is_convertible<const Deriverd*, const Base*>::value)); | ||||
|    value_test(false, (boost::is_convertible<const Base*, const Deriverd*>::value)); | ||||
|    value_test(true, (boost::is_convertible<const Deriverd&, const Base&>::value)); | ||||
|    value_test(false, (boost::is_convertible<const Base&, const Deriverd&>::value)); | ||||
|  | ||||
|    value_test(false, (boost::is_convertible<const int *, int*>::value)); | ||||
|    value_test(false, (boost::is_convertible<const int&, int&>::value)); | ||||
|    value_test(true, (boost::is_convertible<int*, int[2]>::value)); | ||||
|    value_test(false, (boost::is_convertible<const int*, int[3]>::value)); | ||||
|    value_test(true, (boost::is_convertible<const int&, int>::value)); | ||||
|    value_test(true, (boost::is_convertible<int(&)[4], const int*>::value)); | ||||
|    value_test(true, (boost::is_convertible<int(&)(int), int(*)(int)>::value)); | ||||
|    value_test(true, (boost::is_convertible<int *, const int*>::value)); | ||||
|    value_test(true, (boost::is_convertible<int&, const int&>::value)); | ||||
|    value_test(true, (boost::is_convertible<int[2], int*>::value)); | ||||
|    value_test(true, (boost::is_convertible<int[2], const int*>::value)); | ||||
|    value_test(false, (boost::is_convertible<const int[2], int*>::value)); | ||||
|  | ||||
|    align_test(int); | ||||
|    align_test(char); | ||||
|    align_test(double); | ||||
|    align_test(int[4]); | ||||
|    align_test(int(*)(int)); | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
|    align_test(char&); | ||||
|    align_test(char (&)(int)); | ||||
|    align_test(char(&)[4]); | ||||
| #endif | ||||
|    align_test(int*); | ||||
|    //align_test(const int); | ||||
|    align_test(VB); | ||||
|    align_test(VD); | ||||
|  | ||||
|    std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; | ||||
|    std::cin.get(); | ||||
|    return failures; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -1,112 +0,0 @@ | ||||
|  // boost::compressed_pair test program    | ||||
|      | ||||
|  //  (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and    | ||||
|  //  distribute this software is granted provided this copyright notice appears    | ||||
|  //  in all copies. This software is provided "as is" without express or implied    | ||||
|  //  warranty, and with no claim as to its suitability for any purpose.    | ||||
|  | ||||
| // common test code for type_traits_test.cpp/call_traits_test.cpp/compressed_pair_test.cpp | ||||
|  | ||||
|  | ||||
| #ifndef BOOST_TYPE_TRAITS_TEST_HPP | ||||
| #define BOOST_TYPE_TRAITS_TEST_HPP | ||||
|  | ||||
| // | ||||
| // this one is here just to suppress warnings: | ||||
| // | ||||
| template <class T> | ||||
| bool do_compare(T i, T j) | ||||
| { | ||||
|    return i == j; | ||||
| } | ||||
|  | ||||
| // | ||||
| // this one is to verify that a constant is indeed a | ||||
| // constant-integral-expression: | ||||
| // | ||||
| template <int> | ||||
| struct ct_checker | ||||
| { | ||||
| }; | ||||
|  | ||||
| #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) | ||||
| #define BOOST_DO_JOIN2(X, Y) X##Y | ||||
| #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) | ||||
|  | ||||
| #ifdef BOOST_MSVC | ||||
| #define value_test(v, x) ++test_count;\ | ||||
|                         {typedef ct_checker<(x)> this_is_a_compile_time_check_;}\ | ||||
|                          if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} | ||||
| #else | ||||
| #define value_test(v, x) ++test_count;\ | ||||
|                          typedef ct_checker<(x)> BOOST_JOIN(this_is_a_compile_time_check_, __LINE__);\ | ||||
|                          if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} | ||||
| #endif | ||||
| #define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl; | ||||
|  | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
| #define type_test(v, x)  ++test_count;\ | ||||
|                            if(do_compare(boost::is_same<v, x>::value, false)){\ | ||||
|                            ++failures; \ | ||||
|                            std::cout << "checking type of " << #x << "...failed" << std::endl; \ | ||||
|                            std::cout << "   expected type was " << #v << std::endl; \ | ||||
|                            std::cout << "   " << typeid(boost::is_same<v, x>).name() << "::value is false" << std::endl; } | ||||
| #else | ||||
| #define type_test(v, x)  ++test_count;\ | ||||
|                          if(typeid(v) != typeid(x)){\ | ||||
|                            ++failures; \ | ||||
|                            std::cout << "checking type of " << #x << "...failed" << std::endl; \ | ||||
|                            std::cout << "   expected type was " << #v << std::endl; \ | ||||
|                            std::cout << "   " << "typeid(" #v ") != typeid(" #x ")" << std::endl; } | ||||
| #endif | ||||
|  | ||||
| template <class T> | ||||
| struct test_align | ||||
| { | ||||
|    struct padded | ||||
|    { | ||||
|       char c; | ||||
|       T t; | ||||
|    }; | ||||
|    static void do_it() | ||||
|    { | ||||
|       padded p; | ||||
|       unsigned a = reinterpret_cast<char*>(&(p.t)) - reinterpret_cast<char*>(&p); | ||||
|       value_test(a, boost::alignment_of<T>::value); | ||||
|    } | ||||
| }; | ||||
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | ||||
| template <class T> | ||||
| struct test_align<T&> | ||||
| { | ||||
|    static void do_it() | ||||
|    { | ||||
|       // | ||||
|       // we can't do the usual test because we can't take the address | ||||
|       // of a reference, so check that the result is the same as for a | ||||
|       // pointer type instead: | ||||
|       value_test(boost::alignment_of<T*>::value, boost::alignment_of<T&>::value); | ||||
|    } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| #define align_test(T) test_align<T>::do_it() | ||||
|  | ||||
| // | ||||
| // define tests here | ||||
| unsigned failures = 0; | ||||
| unsigned test_count = 0; | ||||
|  | ||||
| // | ||||
| // turn off some warnings: | ||||
| #ifdef __BORLANDC__ | ||||
| #pragma option -w-8004 | ||||
| #endif | ||||
|  | ||||
| #ifdef BOOST_MSVC | ||||
| #pragma warning (disable: 4018) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #endif // BOOST_TYPE_TRAITS_TEST_HPP | ||||
|  | ||||
							
								
								
									
										46
									
								
								utility.htm
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								utility.htm
									
									
									
									
									
								
							| @@ -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.  The checked_delete() and checked_array_delete() function | ||||
| templates simply <b>delete</b> or <b>delete[]</b> their argument, but also | ||||
| require that their argument be a complete type.  They issue an appropriate | ||||
| compiler error diagnostic if that requirement is not met.  A typical | ||||
| implementation is shown; other implementations may vary:</p> | ||||
|  | ||||
| <pre>    template< typename T > | ||||
|     inline void checked_delete(T const volatile * x) | ||||
|     { | ||||
|         BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point | ||||
|                                           // of instantiation | ||||
|         delete x; | ||||
|     } | ||||
|  | ||||
|     template< typename T > | ||||
|     inline void checked_array_delete(T const volatile * x) | ||||
|     { | ||||
|         BOOST_STATIC_ASSERT( sizeof(T) ); // assert type complete at point | ||||
|                                           // of instantiation | ||||
|         delete [] x; | ||||
|     }</pre> | ||||
|  | ||||
| <p>Contributed by Beman Dawes, based on a suggestion from Dave Abrahams, | ||||
| generalizing an idea from Vladimir Prus, with comments from Rainer Deyke, John | ||||
| Maddock, and others.</p> | ||||
|  | ||||
| <h3>Background</h3> | ||||
|  | ||||
| <p>The C++ Standard specifies that delete on a pointer to an incomplete types is | ||||
| undefined behavior if the type has a non-trivial destructor in  [expr.delete] | ||||
| 5.3.5 paragraph.  No diagnostic is required.  Some but not all | ||||
| compilers issue warnings if the type is incomplete at point of deletion.</p> | ||||
|  | ||||
| <h2> <a name="functions next">Function</a> templates next() and prior()</h2> | ||||
|  | ||||
| <p>Certain data types, such as the C++ Standard Library's forward and | ||||
| @@ -81,7 +121,7 @@ CodeWarrior 5.0, and Microsoft Visual C++ 6.0 sp 3.</p> | ||||
|   <pre>// inside one of your own headers ... | ||||
| #include <boost/utility.hpp> | ||||
|  | ||||
| class ResourceLadenFileSystem : noncopyable { | ||||
| class ResourceLadenFileSystem : boost::noncopyable { | ||||
| ...</pre> | ||||
| </blockquote> | ||||
|  | ||||
| @@ -91,9 +131,11 @@ emphasize that it is to be used only as a base class.  Dave Abrahams notes | ||||
| concern about the effect on compiler optimization of adding (even trivial inline) | ||||
| destructor declarations. He says "Probably this concern is misplaced, because | ||||
| noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p> | ||||
| <h2>Function template tie()</h2> | ||||
| <p>See <a href="tie.html">separate documentation</a>.</p> | ||||
| <hr> | ||||
| <p>Revised  <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan | ||||
| -->28 September, 2000<!--webbot bot="Timestamp" endspan i-checksum="39343" | ||||
| -->22 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13960" | ||||
| --> | ||||
| </p> | ||||
| <p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and | ||||
|   | ||||
		Reference in New Issue
	
	Block a user