mirror of
				https://github.com/boostorg/utility.git
				synced 2025-11-04 02:11:45 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			boost-1.21
			...
			boost-1.20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f0214615b5 | 
							
								
								
									
										424
									
								
								algo_opt_examples.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								algo_opt_examples.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,424 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 * 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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										489
									
								
								c++_type_traits.htm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										489
									
								
								c++_type_traits.htm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,489 @@
 | 
			
		||||
<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>
 | 
			
		||||
@@ -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,8 +79,7 @@ used to 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>
 | 
			
		||||
@@ -92,8 +91,7 @@ used to 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>
 | 
			
		||||
@@ -334,8 +332,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>
 | 
			
		||||
@@ -390,8 +388,7 @@ call_traits 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>
 | 
			
		||||
@@ -423,8 +420,7 @@ call_traits 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>
 | 
			
		||||
@@ -436,17 +432,13 @@ call_traits 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>
 | 
			
		||||
@@ -494,8 +486,8 @@ call_traits 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
 | 
			
		||||
@@ -531,14 +523,14 @@ problem):</h4>
 | 
			
		||||
 | 
			
		||||
<pre>template <class Operation> 
 | 
			
		||||
class binder1st : 
 | 
			
		||||
   public unary_function<typename Operation::second_argument_type, typename Operation::result_type> 
 | 
			
		||||
   public unary_function<Operation::second_argument_type, Operation::result_type> 
 | 
			
		||||
{ 
 | 
			
		||||
protected: 
 | 
			
		||||
   Operation op; 
 | 
			
		||||
   typename Operation::first_argument_type value; 
 | 
			
		||||
   Operation::first_argument_type value; 
 | 
			
		||||
public: 
 | 
			
		||||
   binder1st(const Operation& x, const typename Operation::first_argument_type& y); 
 | 
			
		||||
   typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const; 
 | 
			
		||||
   binder1st(const Operation& x, const Operation::first_argument_type& y); 
 | 
			
		||||
   Operation::result_type operator()(const Operation::second_argument_type& x) const; 
 | 
			
		||||
}; </pre>
 | 
			
		||||
 | 
			
		||||
<p>Now consider what happens in the relatively common case that
 | 
			
		||||
@@ -549,7 +541,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>typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;</pre>
 | 
			
		||||
<pre>Operation::result_type operator()(call_traits<Operation::second_argument_type>::param_type x) const;</pre>
 | 
			
		||||
 | 
			
		||||
<p>Now in the case that <code>Operation::second_argument_type</code>
 | 
			
		||||
is a reference type, the argument is passed as a reference, and
 | 
			
		||||
@@ -583,9 +575,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>
 | 
			
		||||
 | 
			
		||||
@@ -674,10 +666,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
 | 
			
		||||
@@ -695,11 +687,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)
 | 
			
		||||
@@ -714,13 +706,13 @@ declared type:</p>
 | 
			
		||||
<pre>template <class T>
 | 
			
		||||
struct A
 | 
			
		||||
{
 | 
			
		||||
   void foo(typename call_traits<T>::value_type t);
 | 
			
		||||
   void foo(call_traits<T>::value_type t);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
void A<T>::foo(typename call_traits<T>::value_type t)
 | 
			
		||||
void A<T>::foo(call_traits<T>::value_type t)
 | 
			
		||||
{
 | 
			
		||||
   typename call_traits<T>::value_type dup(t); // OK even if T is an array type.
 | 
			
		||||
   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
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@
 | 
			
		||||
#include <typeinfo>
 | 
			
		||||
#include <boost/call_traits.hpp>
 | 
			
		||||
 | 
			
		||||
#include <boost/type_traits/type_traits_test.hpp>
 | 
			
		||||
#include "type_traits_test.hpp"
 | 
			
		||||
//
 | 
			
		||||
// struct contained models a type that contains a type (for example std::pair)
 | 
			
		||||
// arrays are contained by value, and have to be treated as a special case:
 | 
			
		||||
@@ -98,18 +98,18 @@ std::pair<
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// struct call_traits_checker:
 | 
			
		||||
// struct checker:
 | 
			
		||||
// verifies behaviour of contained example:
 | 
			
		||||
//
 | 
			
		||||
template <class T>
 | 
			
		||||
struct call_traits_checker
 | 
			
		||||
struct checker
 | 
			
		||||
{
 | 
			
		||||
   typedef typename boost::call_traits<T>::param_type param_type;
 | 
			
		||||
   void operator()(param_type);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
void call_traits_checker<T>::operator()(param_type p)
 | 
			
		||||
void checker<T>::operator()(param_type p)
 | 
			
		||||
{
 | 
			
		||||
   T t(p);
 | 
			
		||||
   contained<T> c(t);
 | 
			
		||||
@@ -117,19 +117,18 @@ void call_traits_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 call_traits_checker<T[N]>
 | 
			
		||||
struct checker<T[N]>
 | 
			
		||||
{
 | 
			
		||||
   typedef typename boost::call_traits<T[N]>::param_type param_type;
 | 
			
		||||
   void operator()(param_type t)
 | 
			
		||||
@@ -177,32 +176,32 @@ void check_make_pair(T c, U u, V v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct comparible_UDT
 | 
			
		||||
struct UDT
 | 
			
		||||
{
 | 
			
		||||
   int i_;
 | 
			
		||||
   comparible_UDT() : i_(2){}
 | 
			
		||||
   bool operator == (const comparible_UDT& v){ return v.i_ == i_; }
 | 
			
		||||
   UDT() : i_(2){}
 | 
			
		||||
   bool operator == (const UDT& v){ return v.i_ == i_; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[ ])
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
   call_traits_checker<comparible_UDT> c1;
 | 
			
		||||
   comparible_UDT u;
 | 
			
		||||
   checker<UDT> c1;
 | 
			
		||||
   UDT u;
 | 
			
		||||
   c1(u);
 | 
			
		||||
   call_traits_checker<int> c2;
 | 
			
		||||
   checker<int> c2;
 | 
			
		||||
   int i = 2;
 | 
			
		||||
   c2(i);
 | 
			
		||||
   int* pi = &i;
 | 
			
		||||
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
 | 
			
		||||
   call_traits_checker<int*> c3;
 | 
			
		||||
   checker<int*> c3;
 | 
			
		||||
   c3(pi);
 | 
			
		||||
   call_traits_checker<int&> c4;
 | 
			
		||||
   checker<int&> c4;
 | 
			
		||||
   c4(i);
 | 
			
		||||
   call_traits_checker<const int&> c5;
 | 
			
		||||
   checker<const int&> c5;
 | 
			
		||||
   c5(i);
 | 
			
		||||
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
 | 
			
		||||
   int a[2] = {1,2};
 | 
			
		||||
   call_traits_checker<int[2]> c6;
 | 
			
		||||
   checker<int[2]> c6;
 | 
			
		||||
   c6(a);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
@@ -221,10 +220,10 @@ int main(int argc, char *argv[ ])
 | 
			
		||||
   typedef int& r_type;
 | 
			
		||||
   typedef const r_type cr_type;
 | 
			
		||||
 | 
			
		||||
   type_test(comparible_UDT, boost::call_traits<comparible_UDT>::value_type)
 | 
			
		||||
   type_test(comparible_UDT&, boost::call_traits<comparible_UDT>::reference)
 | 
			
		||||
   type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::const_reference)
 | 
			
		||||
   type_test(const comparible_UDT&, boost::call_traits<comparible_UDT>::param_type)
 | 
			
		||||
   type_test(UDT, boost::call_traits<UDT>::value_type)
 | 
			
		||||
   type_test(UDT&, boost::call_traits<UDT>::reference)
 | 
			
		||||
   type_test(const UDT&, boost::call_traits<UDT>::const_reference)
 | 
			
		||||
   type_test(const UDT&, boost::call_traits<UDT>::param_type)
 | 
			
		||||
   type_test(int, boost::call_traits<int>::value_type)
 | 
			
		||||
   type_test(int&, boost::call_traits<int>::reference)
 | 
			
		||||
   type_test(const int&, boost::call_traits<int>::const_reference)
 | 
			
		||||
@@ -272,7 +271,9 @@ int main(int argc, char *argv[ ])
 | 
			
		||||
   test_count += 20;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
   return check_result(argc, argv);
 | 
			
		||||
   std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
 | 
			
		||||
   std::cin.get();
 | 
			
		||||
   return failures;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
@@ -363,15 +364,3 @@ template struct call_traits_test<int[2], true>;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef BOOST_MSVC
 | 
			
		||||
unsigned int expected_failures = 10;
 | 
			
		||||
#elif defined(__BORLANDC__)
 | 
			
		||||
unsigned int expected_failures = 2;
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
unsigned int expected_failures = 4;
 | 
			
		||||
#else
 | 
			
		||||
unsigned int expected_failures = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,15 @@
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#include <boost/compressed_pair.hpp>
 | 
			
		||||
#include <boost/type_traits/type_traits_test.hpp>
 | 
			
		||||
#include "type_traits_test.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace boost;
 | 
			
		||||
 | 
			
		||||
struct empty_POD_UDT{};
 | 
			
		||||
struct empty_UDT
 | 
			
		||||
{
 | 
			
		||||
  ~empty_UDT(){};
 | 
			
		||||
};
 | 
			
		||||
namespace boost {
 | 
			
		||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
 | 
			
		||||
template <> struct is_empty<empty_UDT>
 | 
			
		||||
@@ -54,7 +59,7 @@ struct non_empty2
 | 
			
		||||
   { return a.i == b.i; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[ ])
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
   compressed_pair<int, double> cp1(1, 1.3);
 | 
			
		||||
   assert(cp1.first() == 1);
 | 
			
		||||
@@ -96,13 +101,15 @@ int main(int argc, char *argv[ ])
 | 
			
		||||
   cp7.first();
 | 
			
		||||
   double* pd = cp7.second();
 | 
			
		||||
#endif
 | 
			
		||||
   soft_value_test(true, (sizeof(compressed_pair<empty_UDT, int>) < sizeof(std::pair<empty_UDT, int>)))
 | 
			
		||||
   soft_value_test(true, (sizeof(compressed_pair<int, empty_UDT>) < sizeof(std::pair<int, empty_UDT>)))
 | 
			
		||||
   soft_value_test(true, (sizeof(compressed_pair<empty_UDT, empty_UDT>) < sizeof(std::pair<empty_UDT, empty_UDT>)))
 | 
			
		||||
   soft_value_test(true, (sizeof(compressed_pair<empty_UDT, empty_POD_UDT>) < sizeof(std::pair<empty_UDT, empty_POD_UDT>)))
 | 
			
		||||
   soft_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> >)))
 | 
			
		||||
   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> >)))
 | 
			
		||||
 | 
			
		||||
   return check_result(argc, argv);
 | 
			
		||||
   std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
 | 
			
		||||
   std::cin.get();
 | 
			
		||||
   return failures;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
@@ -147,8 +154,6 @@ template compressed_pair<double, int[2]>::compressed_pair();
 | 
			
		||||
#endif // __MWERKS__
 | 
			
		||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
 | 
			
		||||
unsigned int expected_failures = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,325 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
 | 
			
		||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
 | 
			
		||||
<meta name="ProgId" content="FrontPage.Editor.Document">
 | 
			
		||||
<title>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 -->28 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14390" --></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
 | 
			
		||||
 -->
 | 
			
		||||
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
 | 
			
		||||
// distribute this software is granted provided this copyright notice appears
 | 
			
		||||
// in all copies. This software is provided "as is" without express or implied
 | 
			
		||||
// warranty, and with no claim as to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <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;
 | 
			
		||||
}
 | 
			
		||||
@@ -6,11 +6,6 @@
 | 
			
		||||
//  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)
 | 
			
		||||
@@ -23,7 +18,6 @@
 | 
			
		||||
#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>
 | 
			
		||||
@@ -152,7 +146,7 @@ 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
 | 
			
		||||
@@ -160,67 +154,11 @@ void test_container(Container* = 0)  // default arg works around MSVC bug
 | 
			
		||||
    std::advance(finish, c.size() - 1);
 | 
			
		||||
    
 | 
			
		||||
    test(start, finish);
 | 
			
		||||
 | 
			
		||||
    typedef typename Container::const_iterator const_iterator;
 | 
			
		||||
    test(const_iterator(start), const_iterator(finish));
 | 
			
		||||
    
 | 
			
		||||
    test(static_cast<typename Container::const_iterator>(start),
 | 
			
		||||
         static_cast<typename Container::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.
 | 
			
		||||
@@ -238,26 +176,14 @@ int main()
 | 
			
		||||
    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
 | 
			
		||||
    // 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
 | 
			
		||||
#ifndef BOOST_NO_SLIST
 | 
			
		||||
    test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
 | 
			
		||||
# endif
 | 
			
		||||
    
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,273 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
 | 
			
		||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
 | 
			
		||||
<meta name="ProgId" content="FrontPage.Editor.Document">
 | 
			
		||||
<title>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>
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
// 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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
// (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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,169 +0,0 @@
 | 
			
		||||
<!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>
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
//  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>
 | 
			
		||||
@@ -141,6 +140,7 @@ void category_test_2(
 | 
			
		||||
        assert(!greater(ri,rj));
 | 
			
		||||
        assert(!less(ri,rj));
 | 
			
		||||
    }
 | 
			
		||||
#if 0
 | 
			
		||||
    else if (one_empty)
 | 
			
		||||
    {
 | 
			
		||||
        const range& empty = ri.empty() ? ri : rj;
 | 
			
		||||
@@ -184,6 +184,7 @@ void category_test_2(
 | 
			
		||||
            assert(greater_equal(ri,rj));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -304,10 +305,10 @@ void test(T x0, T x1, T x2, T x3)
 | 
			
		||||
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);
 | 
			
		||||
    const Integer a = 0;
 | 
			
		||||
    const Integer b = a + unsigned_random(128 - a);
 | 
			
		||||
    const Integer c = b + unsigned_random(128 - b);
 | 
			
		||||
    const Integer d = c + unsigned_random(128 - c);
 | 
			
		||||
 | 
			
		||||
    test(a, b, c, d);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,11 +23,8 @@
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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>
 | 
			
		||||
#ifndef BOOST_TYPE_TRAITS_HPP
 | 
			
		||||
#include <boost/type_traits.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace boost{
 | 
			
		||||
 
 | 
			
		||||
@@ -19,11 +19,8 @@
 | 
			
		||||
#define BOOST_DETAIL_COMPRESSED_PAIR_HPP
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#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>
 | 
			
		||||
#ifndef BOOST_TYPE_TRAITS_HPP
 | 
			
		||||
#include <boost/type_traits.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef BOOST_CALL_TRAITS_HPP
 | 
			
		||||
#include <boost/call_traits.hpp>
 | 
			
		||||
@@ -425,4 +422,3 @@ swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
 | 
			
		||||
#endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,11 +24,8 @@
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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>
 | 
			
		||||
#ifndef BOOST_TYPE_TRAITS_HPP
 | 
			
		||||
#include <boost/type_traits.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace boost{
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,8 @@
 | 
			
		||||
#define BOOST_OB_COMPRESSED_PAIR_HPP
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#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>
 | 
			
		||||
#ifndef BOOST_TYPE_TRAITS_HPP
 | 
			
		||||
#include <boost/type_traits.hpp>
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef BOOST_CALL_TRAITS_HPP
 | 
			
		||||
#include <boost/call_traits.hpp>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,6 @@
 | 
			
		||||
//  See http://www.boost.org for most recent version including documentation.
 | 
			
		||||
 | 
			
		||||
//  Revision History
 | 
			
		||||
//  11 Feb 01 Fixed bugs in the iterator helpers which prevented explicitly
 | 
			
		||||
//            supplied arguments from actually being used (Dave Abrahams)
 | 
			
		||||
//  04 Jul 00 Fixed NO_OPERATORS_IN_NAMESPACE bugs, major cleanup and
 | 
			
		||||
//            refactoring of compiler workarounds, additional documentation
 | 
			
		||||
//            (Alexy Gurtovoy and Mark Rodgers with some help and prompting from
 | 
			
		||||
@@ -516,7 +514,7 @@ struct forward_iterator_helper
 | 
			
		||||
  : equality_comparable<T
 | 
			
		||||
  , incrementable<T
 | 
			
		||||
  , dereferenceable<T,P
 | 
			
		||||
  , boost::iterator<std::forward_iterator_tag,V,D,P,R
 | 
			
		||||
  , boost::iterator<std::forward_iterator_tag, V, D
 | 
			
		||||
    > > > > {};
 | 
			
		||||
 | 
			
		||||
template <class T,
 | 
			
		||||
@@ -529,7 +527,7 @@ struct bidirectional_iterator_helper
 | 
			
		||||
  , incrementable<T
 | 
			
		||||
  , decrementable<T
 | 
			
		||||
  , dereferenceable<T,P
 | 
			
		||||
  , boost::iterator<std::bidirectional_iterator_tag,V,D,P,R
 | 
			
		||||
  , boost::iterator<std::bidirectional_iterator_tag, V, D
 | 
			
		||||
    > > > > > {};
 | 
			
		||||
 | 
			
		||||
template <class T,
 | 
			
		||||
@@ -546,7 +544,7 @@ struct random_access_iterator_helper
 | 
			
		||||
  , addable2<T,D
 | 
			
		||||
  , subtractable2<T,D
 | 
			
		||||
  , indexable<T,D,R
 | 
			
		||||
  , boost::iterator<std::random_access_iterator_tag,V,D,P,R
 | 
			
		||||
  , boost::iterator<std::random_access_iterator_tag, V, D
 | 
			
		||||
    > > > > > > > > >
 | 
			
		||||
{
 | 
			
		||||
#ifndef __BORLANDC__
 | 
			
		||||
 
 | 
			
		||||
@@ -1,443 +0,0 @@
 | 
			
		||||
<!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 -->28 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14390" -->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
@@ -1,61 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
 | 
			
		||||
// distribute this software is granted provided this copyright notice appears
 | 
			
		||||
// in all copies. This software is provided "as is" without express or implied
 | 
			
		||||
// warranty, and with no claim as to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
#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, 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;
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
  // 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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,151 +0,0 @@
 | 
			
		||||
//  (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;
 | 
			
		||||
}
 | 
			
		||||
@@ -11,15 +11,15 @@
 | 
			
		||||
// Revision History
 | 
			
		||||
// 21 Jan 01 Initial version (Jeremy Siek)
 | 
			
		||||
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#include <boost/pending/iterator_adaptors.hpp>
 | 
			
		||||
#include <boost/detail/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
  typedef boost::iterator_adaptor<std::list<int>::iterator,
 | 
			
		||||
    boost::default_iterator_policies,
 | 
			
		||||
    int,int&,int*,std::bidirectional_iterator_tag> adaptor_type;
 | 
			
		||||
  typedef boost::iterator_adaptor<int*, boost::default_iterator_policies,
 | 
			
		||||
    boost::iterator<std::bidirectional_iterator_tag, int> > adaptor_type;
 | 
			
		||||
  
 | 
			
		||||
  adaptor_type i;
 | 
			
		||||
  i += 4;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,16 +11,16 @@
 | 
			
		||||
// Revision History
 | 
			
		||||
// 21 Jan 01 Initial version (Jeremy Siek)
 | 
			
		||||
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#include <boost/pending/iterator_adaptors.hpp>
 | 
			
		||||
#include <boost/detail/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
  typedef boost::iterator_adaptor<std::istream_iterator<int>,
 | 
			
		||||
    boost::default_iterator_policies,
 | 
			
		||||
    int,int&,int*,std::input_iterator_tag> adaptor_type;
 | 
			
		||||
  typedef boost::iterator_adaptor<int*, boost::default_iterator_policies,
 | 
			
		||||
    boost::iterator<std::input_iterator_tag, int> > adaptor_type;
 | 
			
		||||
  
 | 
			
		||||
  adaptor_type iter;
 | 
			
		||||
  --iter;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								iter_adaptor_fail_expected3.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								iter_adaptor_fail_expected3.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
//  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 <list>
 | 
			
		||||
#include <boost/config.hpp>
 | 
			
		||||
#include <boost/pending/iterator_adaptors.hpp>
 | 
			
		||||
#include <boost/detail/iterator.hpp>
 | 
			
		||||
 | 
			
		||||
class foo {
 | 
			
		||||
public:
 | 
			
		||||
  void bar() { }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
  typedef boost::iterator_adaptor<foo*, boost::default_iterator_policies,
 | 
			
		||||
    boost::iterator<std::input_iterator_tag, foo> > adaptor_type;
 | 
			
		||||
  
 | 
			
		||||
  adaptor_type i;
 | 
			
		||||
  i->bar();
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,61 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify,
 | 
			
		||||
// sell and distribute this software is granted provided this
 | 
			
		||||
// copyright notice appears in all copies. This software is provided
 | 
			
		||||
// "as is" without express or implied warranty, and with no claim as
 | 
			
		||||
// to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
// 8 Mar 2001   Jeremy Siek
 | 
			
		||||
//     Initial checkin.
 | 
			
		||||
 | 
			
		||||
#include <boost/iterator_adaptors.hpp>
 | 
			
		||||
#include <boost/pending/iterator_tests.hpp>
 | 
			
		||||
#include <boost/static_assert.hpp>
 | 
			
		||||
 | 
			
		||||
class bar { };
 | 
			
		||||
void foo(bar) { }
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main()
 | 
			
		||||
{
 | 
			
		||||
  using boost::dummyT;
 | 
			
		||||
  dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), 
 | 
			
		||||
		     dummyT(3), dummyT(4), dummyT(5) };
 | 
			
		||||
  typedef boost::iterator_adaptor<dummyT*, 
 | 
			
		||||
    boost::default_iterator_policies, dummyT> my_iter;
 | 
			
		||||
  my_iter mi(array);
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    typedef boost::iterator_adaptor<my_iter, boost::default_iterator_policies,
 | 
			
		||||
      boost::iterator_traits_generator
 | 
			
		||||
      ::reference<dummyT>
 | 
			
		||||
      ::iterator_category<std::input_iterator_tag> > iter_type;
 | 
			
		||||
 | 
			
		||||
    BOOST_STATIC_ASSERT((boost::is_same<iter_type::iterator_category*,
 | 
			
		||||
       std::input_iterator_tag*>::value));
 | 
			
		||||
 | 
			
		||||
    BOOST_STATIC_ASSERT(( ! boost::is_convertible<iter_type::iterator_category*,
 | 
			
		||||
       std::forward_iterator_tag*>::value));
 | 
			
		||||
 | 
			
		||||
    iter_type i(mi);
 | 
			
		||||
    boost::input_iterator_test(i, dummyT(0), dummyT(1));
 | 
			
		||||
  }
 | 
			
		||||
  {
 | 
			
		||||
    typedef boost::iterator_adaptor<dummyT*,
 | 
			
		||||
      boost::default_iterator_policies,
 | 
			
		||||
      boost::iterator_traits_generator
 | 
			
		||||
        ::value_type<dummyT>
 | 
			
		||||
        ::reference<const dummyT&>
 | 
			
		||||
        ::pointer<const dummyT*> 
 | 
			
		||||
        ::iterator_category<std::forward_iterator_tag>
 | 
			
		||||
        ::difference_type<std::ptrdiff_t> > adaptor_type;
 | 
			
		||||
 | 
			
		||||
    adaptor_type i(array);
 | 
			
		||||
 | 
			
		||||
    boost::input_iterator_test(i, dummyT(0), dummyT(1));
 | 
			
		||||
    int zero = 0;
 | 
			
		||||
    if (zero) // don't do this, just make sure it compiles
 | 
			
		||||
      assert((*i).m_x == i->foo());      
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
//  Test boost/iterator_adaptors.hpp
 | 
			
		||||
//  Demonstrate and test boost/operators.hpp on std::iterators  -------------//
 | 
			
		||||
 | 
			
		||||
//  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
 | 
			
		||||
//  sell and distribute this software is granted provided this
 | 
			
		||||
@@ -9,16 +9,6 @@
 | 
			
		||||
//  See http://www.boost.org for most recent version including documentation.
 | 
			
		||||
 | 
			
		||||
//  Revision History
 | 
			
		||||
//  08 Mar 01 Moved indirect and transform tests to separate files.
 | 
			
		||||
//            (Jeremy Siek)
 | 
			
		||||
//  19 Feb 01 Take adavantage of improved iterator_traits to do more tests
 | 
			
		||||
//            on MSVC. Hack around an MSVC-with-STLport internal compiler
 | 
			
		||||
//            error. (David Abrahams)
 | 
			
		||||
//  11 Feb 01 Added test of operator-> for forward and input iterators.
 | 
			
		||||
//            (Jeremy Siek)
 | 
			
		||||
//  11 Feb 01 Borland fixes (David Abrahams)
 | 
			
		||||
//  10 Feb 01 Use new adaptors interface. (David Abrahams)
 | 
			
		||||
//  10 Feb 01 Use new filter_ interface. (David Abrahams)
 | 
			
		||||
//  09 Feb 01 Use new reverse_ and indirect_ interfaces. Replace
 | 
			
		||||
//            BOOST_NO_STD_ITERATOR_TRAITS with
 | 
			
		||||
//            BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've
 | 
			
		||||
@@ -51,7 +41,6 @@
 | 
			
		||||
#include <boost/iterator_adaptors.hpp>
 | 
			
		||||
#include <boost/pending/iterator_tests.hpp>
 | 
			
		||||
#include <boost/pending/integer_range.hpp>
 | 
			
		||||
#include <boost/concept_archetype.hpp>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <deque>
 | 
			
		||||
@@ -61,6 +50,28 @@ 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_adaptor<dummyT*, 
 | 
			
		||||
  boost::default_iterator_policies, my_iter_traits> my_iterator;
 | 
			
		||||
 | 
			
		||||
typedef boost::iterator_adaptor<const dummyT*, 
 | 
			
		||||
  boost::default_iterator_policies, my_const_iter_traits> const_my_iterator;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct mult_functor {
 | 
			
		||||
  typedef int result_type;
 | 
			
		||||
@@ -97,6 +108,78 @@ 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);
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
{
 | 
			
		||||
@@ -118,14 +201,60 @@ main()
 | 
			
		||||
 | 
			
		||||
  // Test the iterator_adaptor
 | 
			
		||||
  {
 | 
			
		||||
    boost::iterator_adaptor<dummyT*, boost::default_iterator_policies, dummyT> i(array);
 | 
			
		||||
    my_iterator i = array;
 | 
			
		||||
    boost::random_access_iterator_test(i, N, array);
 | 
			
		||||
    
 | 
			
		||||
    boost::iterator_adaptor<const dummyT*, boost::default_iterator_policies, const dummyT> j(array);
 | 
			
		||||
    const_my_iterator j = array;
 | 
			
		||||
    boost::random_access_iterator_test(j, N, array);
 | 
			
		||||
    boost::const_nonconst_iterator_test(i, ++j);
 | 
			
		||||
  }
 | 
			
		||||
  // Test transform_iterator
 | 
			
		||||
  {
 | 
			
		||||
    int x[N], y[N];
 | 
			
		||||
    for (int k = 0; k < N; ++k)
 | 
			
		||||
      x[k] = k;
 | 
			
		||||
    std::copy(x, x + N, y);
 | 
			
		||||
 | 
			
		||||
    for (int k2 = 0; k2 < N; ++k2)
 | 
			
		||||
      x[k2] = x[k2] * 2;
 | 
			
		||||
 | 
			
		||||
    boost::transform_iterator_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]);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // 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);
 | 
			
		||||
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_indirect_iterator<dummyT>(ptr), N, array);
 | 
			
		||||
    
 | 
			
		||||
    const_indirect_iterator j = ptr;
 | 
			
		||||
    boost::random_access_iterator_test(j, N, array);
 | 
			
		||||
 | 
			
		||||
    dummyT*const* const_ptr = ptr;
 | 
			
		||||
    
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_indirect_iterator<const dummyT>(const_ptr), N, array);
 | 
			
		||||
 | 
			
		||||
    boost::const_nonconst_iterator_test(i, ++j);
 | 
			
		||||
 | 
			
		||||
    more_indirect_iterator_tests();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Test projection_iterator_pair_generator
 | 
			
		||||
  {    
 | 
			
		||||
    typedef std::pair<dummyT,dummyT> Pair;
 | 
			
		||||
@@ -137,21 +266,20 @@ main()
 | 
			
		||||
      Pair*, const Pair*
 | 
			
		||||
      > Projection;
 | 
			
		||||
    
 | 
			
		||||
    Projection::iterator i(pair_array);
 | 
			
		||||
    Projection::iterator i = pair_array;
 | 
			
		||||
    boost::random_access_iterator_test(i, N, array);
 | 
			
		||||
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_projection_iterator(pair_array, select1st_<Pair>()), N, array);    
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_projection_iterator< select1st_<Pair> >(pair_array), N, array);    
 | 
			
		||||
 | 
			
		||||
    Projection::const_iterator j(pair_array);
 | 
			
		||||
    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::random_access_iterator_test(boost::make_const_projection_iterator< select1st_<Pair> >(pair_array), N, array);
 | 
			
		||||
 | 
			
		||||
    boost::const_nonconst_iterator_test(i, ++j);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Test reverse_iterator_generator
 | 
			
		||||
  {
 | 
			
		||||
    dummyT reversed[N];
 | 
			
		||||
@@ -164,20 +292,20 @@ main()
 | 
			
		||||
#endif
 | 
			
		||||
      >::type reverse_iterator;
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator i(reversed + N);
 | 
			
		||||
    boost::random_access_iterator_test(i, N, array);
 | 
			
		||||
 | 
			
		||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    typedef boost::reverse_iterator_generator<const dummyT*
 | 
			
		||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
        , const dummyT
 | 
			
		||||
#endif
 | 
			
		||||
      >::type const_reverse_iterator;
 | 
			
		||||
    
 | 
			
		||||
    const_reverse_iterator j(reversed + N);
 | 
			
		||||
    reverse_iterator i = reversed + N;
 | 
			
		||||
    boost::random_access_iterator_test(i, N, array);
 | 
			
		||||
 | 
			
		||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
    boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    const_reverse_iterator j = reversed + N;
 | 
			
		||||
    boost::random_access_iterator_test(j, N, array);
 | 
			
		||||
 | 
			
		||||
    const dummyT* const_reversed = reversed;
 | 
			
		||||
@@ -189,38 +317,34 @@ main()
 | 
			
		||||
    boost::const_nonconst_iterator_test(i, ++j);    
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Test reverse_iterator_generator again, with traits fully deducible on all platforms
 | 
			
		||||
  // Test reverse_iterator_generator again, with traits fully deducible on most platforms
 | 
			
		||||
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
 | 
			
		||||
  {
 | 
			
		||||
    std::deque<dummyT> reversed_container;
 | 
			
		||||
    std::reverse_copy(array, array + N, std::back_inserter(reversed_container));
 | 
			
		||||
    std::copy(array, array + N, std::back_inserter(reversed_container));
 | 
			
		||||
    const std::deque<dummyT>::iterator reversed = reversed_container.begin();
 | 
			
		||||
 | 
			
		||||
    std::reverse(reversed, reversed + N);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator i = reversed + N;
 | 
			
		||||
    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);
 | 
			
		||||
    const_reverse_iterator j = reverse_iterator(reversed + N);
 | 
			
		||||
    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)
 | 
			
		||||
#if !defined(__GNUC__) || defined(__SGI_STL_PORT)  // GCC deque iterators don't allow all const/non-const comparisons
 | 
			
		||||
    boost::const_nonconst_iterator_test(i, ++j);
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  
 | 
			
		||||
  // Test integer_range's iterators
 | 
			
		||||
  {
 | 
			
		||||
@@ -231,104 +355,30 @@ main()
 | 
			
		||||
 | 
			
		||||
  // 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));
 | 
			
		||||
    typedef boost::filter_iterator_generator<one_or_four, dummyT*,
 | 
			
		||||
      boost::iterator<std::forward_iterator_tag, dummyT, std::ptrdiff_t,
 | 
			
		||||
      dummyT*, dummyT&> > FilterGen;
 | 
			
		||||
    typedef FilterGen::type FilterIter;
 | 
			
		||||
    typedef FilterGen::policies_type FilterPolicies;
 | 
			
		||||
    FilterIter i(array, FilterPolicies(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
 | 
			
		||||
    typedef boost::iterator<std::forward_iterator_tag, dummyT, std::ptrdiff_t, dummyT*, dummyT&> FilterTraits;
 | 
			
		||||
    boost::forward_iterator_test(boost::make_filter_iterator<FilterTraits>
 | 
			
		||||
       (array, array + N, one_or_four() ), dummyT(1), dummyT(4));
 | 
			
		||||
 | 
			
		||||
    // 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<FilterTraits, one_or_four>
 | 
			
		||||
        (array, array + N), dummyT(1), dummyT(4));
 | 
			
		||||
 | 
			
		||||
    boost::forward_iterator_test(
 | 
			
		||||
        boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()),
 | 
			
		||||
        dummyT(1), dummyT(4));
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
    boost::forward_iterator_test(boost::make_filter_iterator(
 | 
			
		||||
        array, array + N, one_or_four()), dummyT(1), dummyT(4));
 | 
			
		||||
 | 
			
		||||
#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));
 | 
			
		||||
    boost::forward_iterator_test(boost::make_filter_iterator<one_or_four>(
 | 
			
		||||
        array, array + N), dummyT(1), dummyT(4));
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | 
			
		||||
    boost::forward_iterator_test(
 | 
			
		||||
        boost::make_filter_iterator(array+0, array+N, one_or_four()),
 | 
			
		||||
        dummyT(1), dummyT(4));
 | 
			
		||||
 | 
			
		||||
    boost::forward_iterator_test(
 | 
			
		||||
        boost::make_filter_iterator<one_or_four>(array, array + N),
 | 
			
		||||
        dummyT(1), dummyT(4));
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // check operator-> with a forward iterator
 | 
			
		||||
  {
 | 
			
		||||
    boost::forward_iterator_archetype<dummyT> forward_iter;
 | 
			
		||||
#if defined(__BORLANDC__)
 | 
			
		||||
    typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
 | 
			
		||||
      boost::default_iterator_policies,
 | 
			
		||||
      dummyT, const dummyT&, const dummyT*, 
 | 
			
		||||
      std::forward_iterator_tag, std::ptrdiff_t> adaptor_type;
 | 
			
		||||
#else
 | 
			
		||||
    typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
 | 
			
		||||
      boost::default_iterator_policies,
 | 
			
		||||
      boost::iterator_traits_generator
 | 
			
		||||
        ::value_type<dummyT>
 | 
			
		||||
        ::reference<const dummyT&>
 | 
			
		||||
        ::pointer<const dummyT*> 
 | 
			
		||||
        ::iterator_category<std::forward_iterator_tag>
 | 
			
		||||
        ::difference_type<std::ptrdiff_t> > adaptor_type;
 | 
			
		||||
#endif
 | 
			
		||||
    adaptor_type i(forward_iter);
 | 
			
		||||
    int zero = 0;
 | 
			
		||||
    if (zero) // don't do this, just make sure it compiles
 | 
			
		||||
      assert((*i).m_x == i->foo());      
 | 
			
		||||
  }
 | 
			
		||||
  // check operator-> with an input iterator
 | 
			
		||||
  {
 | 
			
		||||
    boost::input_iterator_archetype<dummyT> input_iter;
 | 
			
		||||
    typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>,
 | 
			
		||||
      boost::default_iterator_policies,
 | 
			
		||||
      dummyT, const dummyT&, const dummyT*, 
 | 
			
		||||
      std::input_iterator_tag, std::ptrdiff_t> adaptor_type;
 | 
			
		||||
    adaptor_type i(input_iter);
 | 
			
		||||
    int zero = 0;
 | 
			
		||||
    if (zero) // don't do this, just make sure it compiles
 | 
			
		||||
      assert((*i).m_x == i->foo());      
 | 
			
		||||
  }
 | 
			
		||||
  std::cout << "test successful " << std::endl;
 | 
			
		||||
  return 0;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -7,14 +7,6 @@
 | 
			
		||||
//  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
 | 
			
		||||
@@ -31,54 +23,20 @@
 | 
			
		||||
#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&>
 | 
			
		||||
struct my_iterator
 | 
			
		||||
    : public boost::forward_iterator_helper<my_iterator, const char, long>
 | 
			
		||||
{
 | 
			
		||||
    my_iterator1(const char* p) : m_p(p) {}
 | 
			
		||||
    my_iterator(const char* p) : m_p(p) {}
 | 
			
		||||
    
 | 
			
		||||
    bool operator==(const my_iterator1& rhs) const
 | 
			
		||||
    bool operator==(const my_iterator& rhs) const
 | 
			
		||||
        { return this->m_p == rhs.m_p; }
 | 
			
		||||
 | 
			
		||||
    my_iterator1& operator++() { ++this->m_p; return *this; }
 | 
			
		||||
    my_iterator& 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>
 | 
			
		||||
@@ -132,7 +90,9 @@ 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>
 | 
			
		||||
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
 | 
			
		||||
      , non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
 | 
			
		||||
#endif
 | 
			
		||||
{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -149,21 +109,14 @@ struct maybe_pointer_test
 | 
			
		||||
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;
 | 
			
		||||
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
 | 
			
		||||
    void,
 | 
			
		||||
#else // the VC6 standard lib gives ostream_iterator an incorrect value_type
 | 
			
		||||
    int,
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    void, void, void, std::output_iterator_tag>
 | 
			
		||||
        ostream_iterator_test;
 | 
			
		||||
 | 
			
		||||
#ifdef __KCC
 | 
			
		||||
  typedef long std_list_diff_type;
 | 
			
		||||
@@ -179,14 +132,8 @@ maybe_pointer_test<std::vector<int>::iterator, int, std::ptrdiff_t, int*, int&,
 | 
			
		||||
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;
 | 
			
		||||
non_pointer_test<my_iterator, const char, long, const char*, const char&, std::forward_iterator_tag>
 | 
			
		||||
       my_iterator_test;
 | 
			
		||||
                    
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
@@ -202,9 +149,7 @@ int main()
 | 
			
		||||
        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);
 | 
			
		||||
        assert(boost::detail::distance(my_iterator(chars), my_iterator(chars + length)) == length);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
//  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
 | 
			
		||||
@@ -350,15 +349,8 @@ void test(Number* = 0)
 | 
			
		||||
              << "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::numeric_traits<Number>::difference_type difference_type;
 | 
			
		||||
    BOOST_STATIC_ASSERT(boost::detail::is_signed<difference_type>::value);
 | 
			
		||||
 | 
			
		||||
    typedef typename boost::detail::if_true<
 | 
			
		||||
        boost::detail::is_signed<Number>::value
 | 
			
		||||
 
 | 
			
		||||
@@ -1,391 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
 | 
			
		||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
 | 
			
		||||
<meta name="ProgId" content="FrontPage.Editor.Document">
 | 
			
		||||
<title>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 -->28 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14390" --></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
 | 
			
		||||
 -->
 | 
			
		||||
@@ -1,96 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
 | 
			
		||||
// distribute this software is granted provided this copyright notice appears
 | 
			
		||||
// in all copies. This software is provided "as is" without express or implied
 | 
			
		||||
// warranty, and with no claim as to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
#include <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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,331 +0,0 @@
 | 
			
		||||
<!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 -->28 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14390" -->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
 | 
			
		||||
@@ -1,42 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
 | 
			
		||||
// distribute this software is granted provided this copyright notice appears
 | 
			
		||||
// in all copies. This software is provided "as is" without express or implied
 | 
			
		||||
// warranty, and with no claim as to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
#include <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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,215 +0,0 @@
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
 | 
			
		||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
 | 
			
		||||
<meta name="ProgId" content="FrontPage.Editor.Document">
 | 
			
		||||
<title>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.
 | 
			
		||||
 | 
			
		||||
<p>
 | 
			
		||||
<PRE>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <boost/iterator_adaptors.hpp>
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int, char*[])
 | 
			
		||||
{
 | 
			
		||||
  int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
 | 
			
		||||
 | 
			
		||||
  typedef std::binder1st< std::multiplies<int> > Function;
 | 
			
		||||
  typedef boost::transform_iterator_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));
 | 
			
		||||
 | 
			
		||||
  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.</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, std::bind1st(std::plus<int>(), 4)),
 | 
			
		||||
	    boost::make_transform_iterator(x + N, std::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 -->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>
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
 | 
			
		||||
// distribute this software is granted provided this copyright notice appears
 | 
			
		||||
// in all copies. This software is provided "as is" without express or implied
 | 
			
		||||
// warranty, and with no claim as to its suitability for any purpose.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <boost/iterator_adaptors.hpp>
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int, char*[])
 | 
			
		||||
{
 | 
			
		||||
  // This is a simple example of using the transform_iterators class to
 | 
			
		||||
  // generate iterators that multiply the value returned by dereferencing
 | 
			
		||||
  // the iterator. In this case we are multiplying by 2.
 | 
			
		||||
  // 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 std::binder1st< std::multiplies<int> > Function;
 | 
			
		||||
  typedef boost::transform_iterator_generator<Function, int*>::type doubling_iterator;
 | 
			
		||||
 | 
			
		||||
  doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
 | 
			
		||||
    i_end(x + N, std::bind1st(std::multiplies<int>(), 2));
 | 
			
		||||
 | 
			
		||||
  std::cout << "multiplying the array by 2:" << std::endl;
 | 
			
		||||
  while (i != i_end)
 | 
			
		||||
    std::cout << *i++ << " ";
 | 
			
		||||
  std::cout << std::endl;
 | 
			
		||||
 | 
			
		||||
  std::cout << "adding 4 to each element in the array:" << std::endl;
 | 
			
		||||
 | 
			
		||||
  std::copy(boost::make_transform_iterator(x, std::bind1st(std::plus<int>(), 4)),
 | 
			
		||||
	    boost::make_transform_iterator(x + N, std::bind1st(std::plus<int>(), 4)),
 | 
			
		||||
	    std::ostream_iterator<int>(std::cout, " "));
 | 
			
		||||
  std::cout << std::endl;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
//  (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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										620
									
								
								type_traits.htm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,620 @@
 | 
			
		||||
<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>
 | 
			
		||||
							
								
								
									
										672
									
								
								type_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										672
									
								
								type_traits_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,672 @@
 | 
			
		||||
//  (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:
 | 
			
		||||
   31 Jan 2001:
 | 
			
		||||
      Added a test for is_array using a const array and a test for
 | 
			
		||||
      is_convertible with a user-defined implicit conversion. Changed
 | 
			
		||||
      signature of main() so that this program will link under
 | 
			
		||||
      MSVC. (Jeremy Siek)
 | 
			
		||||
   20 Jan 2001:
 | 
			
		||||
      Suppress an expected warning for MSVC
 | 
			
		||||
      Added a test to prove that we can use void with is_same<>
 | 
			
		||||
      Removed "press any key to exit" as it interferes with testing in large
 | 
			
		||||
      batches.
 | 
			
		||||
      (David Abahams)
 | 
			
		||||
   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 Derived : 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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct implicitly_convertible_to_int {
 | 
			
		||||
  operator int() { return 0; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 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(int, char*[])
 | 
			
		||||
{
 | 
			
		||||
   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;
 | 
			
		||||
#ifdef BOOST_MSVC
 | 
			
		||||
# pragma warning(push)
 | 
			
		||||
# pragma warning(disable:4181) // qualifier applied to reference type ignored
 | 
			
		||||
#endif
 | 
			
		||||
   typedef const r_type cr_type;
 | 
			
		||||
#ifdef BOOST_MSVC
 | 
			
		||||
# pragma warning(pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
   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<void, void>::value))
 | 
			
		||||
   value_test(false, (is_same<int, void>::value))
 | 
			
		||||
   value_test(false, (is_same<void, int>::value))
 | 
			
		||||
   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)
 | 
			
		||||
   value_test(true, is_array<const 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<implicitly_convertible_to_int, 
 | 
			
		||||
                                          int>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<Derived,Base>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<Derived,Derived>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<Base,Base>::value));
 | 
			
		||||
   value_test(false, (boost::is_convertible<Base,Derived>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<Derived,Derived>::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<Derived*, Base*>::value));
 | 
			
		||||
   value_test(false, (boost::is_convertible<Base*, Derived*>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<Derived&, Base&>::value));
 | 
			
		||||
   value_test(false, (boost::is_convertible<Base&, Derived&>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<const Derived*, const Base*>::value));
 | 
			
		||||
   value_test(false, (boost::is_convertible<const Base*, const Derived*>::value));
 | 
			
		||||
   value_test(true, (boost::is_convertible<const Derived&, const Base&>::value));
 | 
			
		||||
   value_test(false, (boost::is_convertible<const Base&, const Derived&>::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)";
 | 
			
		||||
   return failures;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										114
									
								
								type_traits_test.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								type_traits_test.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
// Variable declarations must come before test_align due to two-phase lookup
 | 
			
		||||
unsigned failures = 0;
 | 
			
		||||
unsigned test_count = 0;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +81,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 : boost::noncopyable {
 | 
			
		||||
class ResourceLadenFileSystem : noncopyable {
 | 
			
		||||
...</pre>
 | 
			
		||||
</blockquote>
 | 
			
		||||
 | 
			
		||||
@@ -93,7 +93,7 @@ destructor declarations. He says "Probably this concern is misplaced, becau
 | 
			
		||||
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p>
 | 
			
		||||
<hr>
 | 
			
		||||
<p>Revised  <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
 | 
			
		||||
-->28 February, 2001<!--webbot bot="Timestamp" endspan i-checksum="40412"
 | 
			
		||||
-->28 September, 2000<!--webbot bot="Timestamp" endspan i-checksum="39343"
 | 
			
		||||
-->
 | 
			
		||||
</p>
 | 
			
		||||
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user