diff --git a/Assignable.html b/Assignable.html deleted file mode 100644 index a13357d..0000000 --- a/Assignable.html +++ /dev/null @@ -1,116 +0,0 @@ - - -
--T - | --is type that is a model of Assignable - | -
-t - | --is an object of type T - | -
-u - | --is an object of type T or possibly const T - | -
-Name - | --Expression - | --Return type - | --Semantics - | -
---|---|---|---|
-Assignment - | --t = u - | --T& - | --t is equivalent to u - | -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
-T - | --is type that is a model of Copy Constructible - | -
-t - | --is an object of type T - | -
-u - | --is an object of type const T - | -
-Name - | --Expression - | --Return type - | --Semantics - | -
---|---|---|---|
-Copy constructor - | --T(t) - | --T - | --t is equivalent to T(t) - | -
-Copy constructor - | -
--T(u) -- |
--T - | --u is equivalent to T(u) - | -
-Destructor - | -
--t.~T() -- |
--T - | -- - | -
-Address Operator - | -
--&t -- |
--T* - | --denotes the address of t - | -
-Address Operator - | -
--&u -- |
--T* - | --denotes the address of u - | -
- template <class T> - struct CopyConstructibleConcept - { - void constraints() { - T a(b); // require copy constructor - T* ptr = &a; // require address of operator - const_constraints(a); - ignore_unused_variable_warning(ptr); - } - void const_constraints(const T& a) { - T c(a); // require const copy constructor - const T* ptr = &a; // require const address of operator - ignore_unused_variable_warning(c); - ignore_unused_variable_warning(ptr); - } - T b; - }; -- -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
-X - | --A type that is a model of LessThanComparable - | -
-x, y, z - | --Object of type X - | -
-If operator< is a strict weak ordering, and if each equivalence class -has only a single element, then operator< is a total ordering. -
-Name - | --Expression - | --Type requirements - | --Return type - | -
---|---|---|---|
-Less - | --x < y - | -- - | --Convertible to bool - | -
-Name - | --Expression - | --Precondition - | --Semantics - | --Postcondition - | -
---|---|---|---|---|
-Less - | --x < y - | --x and y are in the domain of < - | -- - | -
-Irreflexivity - | --x < x must be false. - | -
-Antisymmetry - | --x < y implies !(y < x) [2] - | -
-Transitivity - | --x < y and y < z implies x < z [3] - | -
[1] -Only operator< is fundamental; the other inequality operators -are essentially syntactic sugar. -
[2] -Antisymmetry is a theorem, not an axiom: it follows from -irreflexivity and transitivity. -
[3] -Because of irreflexivity and transitivity, operator< always -satisfies the definition of a partial ordering. The definition of -a strict weak ordering is stricter, and the definition of a -total ordering is stricter still. -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
I think that introducing Multi-Pass Input Iterator isn't the right -solution. Do you also want to define Multi-Pass Bidirectionnal Iterator -and Multi-Pass Random Access Iterator ? I don't, definitly. It only -confuses the issue. The problem lies into the existing hierarchy of -iterators, which mixes movabillity, modifiabillity and lvalue-ness, -and these are clearly independant. - -
The terms Forward, Bidirectionnal and Random Access are about -movabillity and shouldn't be used to mean anything else. In a -completly orthogonal way, iterators can be immutable, mutable, or -neither. Lvalueness of iterators is also orthogonal with -immutabillity. With these clean concepts, your Multi-Pass Input Iterator -is just called a Forward Iterator. - -
-Other translations are:
-std::Forward Iterator -> ForwardIterator & Lvalue Iterator
-std::Bidirectionnal Iterator -> Bidirectionnal Iterator & Lvalue Iterator
-std::Random Access Iterator -> Random Access Iterator & Lvalue Iterator
-
-
-Note that in practice the only operation not allowed on my -Forward Iterator which is allowed on std::Forward Iterator is -&*it. I think that &* is rarely needed in generic code. - -
-reply by Jeremy Siek: - -
-The above analysis by Valentin is right on. Of course, there is
-the problem with backward compatibility. The current STL implementations
-are based on the old definition of Forward Iterator. The right course
-of action is to get Forward Iterator, etc. changed in the C++ standard.
-Once that is done we can drop Multi-Pass Input Iterator.
-
-
-
-
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
The class template boost::base_from_member
provides
-a workaround for a class that needs to initialize a base class with a
-member. The class template is in boost/utility/base_from_member.hpp
-which is included in boost/utility.hpp.
-The class template is forward declared in boost/utility_fwd.hpp.
There is test/example code in base_from_member_test.cpp.
- -When developing a class, sometimes a base class needs to be -initialized with a member of the current class. As a naïve -example:
- -- --#include <streambuf> // for std::streambuf -#include <ostream> // for std::ostream - -class fdoutbuf - : public std::streambuf -{ -public: - explicit fdoutbuf( int fd ); - //... -}; - -class fdostream - : public std::ostream -{ -protected: - fdoutbuf buf; -public: - explicit fdostream( int fd ) - : buf( fd ), std::ostream( &buf ) - {} - //... -}; -
This is undefined because C++'s initialization order mandates that -the base class is initialized before the member it uses. Ron Klatchko -developed a way around this by using the initialization order in his -favor. Base classes are intialized in order of declaration, so moving -the desired member to another base class, that is initialized before the -desired base class, can ensure proper initialization.
- -A custom base class can be made for this idiom:
- -- --#include <streambuf> // for std::streambuf -#include <ostream> // for std::ostream - -class fdoutbuf - : public std::streambuf -{ -public: - explicit fdoutbuf( int fd ); - //... -}; - -struct fdostream_pbase -{ - fdoutbuf sbuffer; - - explicit fdostream_pbase( int fd ) - : sbuffer( fd ) - {} -}; - -class fdostream - : private fdostream_pbase - , public std::ostream -{ - typedef fdostream_pbase pbase_type; - typedef std::ostream base_type; - -public: - explicit fdostream( int fd ) - : pbase_type( fd ), base_type( &sbuffer ) - {} - //... -}; -
Other projects can use similar custom base classes. The technique is basic enough to make a template, with a sample template class in this library. The main template parameter is the type of the enclosed member. The template class has several (explicit) constructor member templates, which implicitly type the constructor arguments and pass them to the member. The template class uses implicit copy construction and assignment, cancelling them if the enclosed member is non-copyable.
- -Manually coding a base class may be better if the construction -and/or copying needs are too complex for the supplied template class, -or if the compiler is not advanced enough to use it.
- -Since base classes are unnamed, a class cannot have multiple (direct) -base classes of the same type. The supplied template class has an -extra template parameter, an integer, that exists solely to provide type -differentiation. This parameter has a default value so a single use of a -particular member type does not need to concern itself with the integer.
- -- --template < typename MemberType, int UniqueID = 0 > -class boost::base_from_member -{ -protected: - MemberType member; - - explicit base_from_member(); - - template< typename T1 > - explicit base_from_member( T1 x1 ); - - //... - - template< typename T1, typename T2, typename T3 > - explicit base_from_member( T1 x1, T2 x2, T3 x3 ); -}; -
The class template has a first template parameter
-MemberType representing the type of the based-member.
-It has a last template parameter UniqueID, that is an
-int
, to differentiate between multiple base classes that use
-the same based-member type. The last template parameter has a default
-value of zero if it is omitted. The class template has a protected
-data member called member that the derived class can use
-for later base classes (or itself).
There is a default constructor and several constructor member -templates. These constructor templates can take as many arguments -(currently up to three) as possible and pass them to a constructor of -the data member. Since C++ does not allow any way to explicitly state -the template parameters of a templated constructor, make sure that -the arguments are already close as possible to the actual type used in -the data member's desired constructor.
- -With the starting example, the fdoutbuf
sub-object needs
-to be encapsulated in a base class that is inheirited before
-std::ostream
.
- --#include <boost/utility/base_from_member.hpp> - -#include <streambuf> // for std::streambuf -#include <ostream> // for std::ostream - -class fdoutbuf - : public std::streambuf -{ -public: - explicit fdoutbuf( int fd ); - //... -}; - -class fdostream - : private boost::base_from_member<fdoutbuf> - , public std::ostream -{ - // Helper typedef's - typedef boost::base_from_member<fdoutbuf> pbase_type; - typedef std::ostream base_type; - -public: - explicit fdostream( int fd ) - : pbase_type( fd ), base_type( &member ) - {} - //... -}; -
The base-from-member idiom is an implementation detail, so it
-should not be visible to the clients (or any derived classes) of
-fdostream
. Due to the initialization order, the
-fdoutbuf
sub-object will get initialized before the
-std::ostream
sub-object does, making the former
-sub-object safe to use in the latter sub-object's construction. Since the
-fdoutbuf
sub-object of the final type is the only sub-object
-with the name "member," that name can be used
-unqualified within the final class.
The base-from-member class templates should commonly involve -only one base-from-member sub-object, usually for attaching a -stream-buffer to an I/O stream. The next example demonstrates how -to use multiple base-from-member sub-objects and the resulting -qualification issues.
- -- --#include <boost/utility/base_from_member.hpp> - -#include <cstddef> // for NULL - -struct an_int -{ - int y; - - an_int( float yf ); -}; - -class switcher -{ -public: - switcher(); - switcher( double, int * ); - //... -}; - -class flow_regulator -{ -public: - flow_regulator( switcher &, switcher & ); - //... -}; - -template < unsigned Size > -class fan -{ -public: - explicit fan( switcher ); - //... -}; - -class system - : private boost::base_from_member<an_int> - , private boost::base_from_member<switcher> - , private boost::base_from_member<switcher, 1> - , private boost::base_from_member<switcher, 2> - , protected flow_regulator - , public fan<6> -{ - // Helper typedef's - typedef boost::base_from_member<an_int> pbase0_type; - typedef boost::base_from_member<switcher> pbase1_type; - typedef boost::base_from_member<switcher, 1> pbase2_type; - typedef boost::base_from_member<switcher, 2> pbase3_type; - - typedef flow_regulator base1_type; - typedef fan<6> base2_type; - -public: - system( double x ); - //... -}; - -system::system( double x ) - : pbase0_type( 0.2 ) - , pbase1_type() - , pbase2_type( -16, &this->pbase0_type::member ) - , pbase3_type( x, static_cast<int *>(NULL) ) - , base1_type( pbase3_type::member, pbase1_type::member ) - , base2_type( pbase2_type::member ) -{ - //... -} -
The final class has multiple sub-objects with the name
-"member," so any use of that name needs qualification by
-a name of the appropriate base type. (Using typedef
s
-ease mentioning the base types.) However, the fix introduces a new
-problem when a pointer is needed. Using the address operator with
-a sub-object qualified with its class's name results in a pointer-to-member
-(here, having a type of an_int boost::base_from_member<an_int,
-0> :: *
) instead of a pointer to the member (having a type of
-an_int *
). The new problem is fixed by qualifying the
-sub-object with "this->
," and is needed just
-for pointers, and not for references or values.
There are some argument conversions in the initialization. The
-constructor argument for pbase0_type
is converted from
-double
to float
. The first constructor
-argument for pbase2_type
is converted from int
-to double
. The second constructor argument for
-pbase3_type
is a special case of necessary conversion; all
-forms of the null-pointer literal in C++ also look like compile-time
-integral expressions, so C++ always interprets such code as an integer
-when it has overloads that can take either an integer or a pointer. The
-last conversion is necessary for the compiler to call a constructor form
-with the exact pointer type used in switcher
's constructor.
Revised: 22 August 2001
- -Copyright © boost.org 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.
- - - diff --git a/base_from_member_test.cpp b/base_from_member_test.cpp deleted file mode 100644 index c422913..0000000 --- a/base_from_member_test.cpp +++ /dev/null @@ -1,597 +0,0 @@ -// Boost test program for base-from-member class templates -----------------// - -// (C) Copyright Daryle Walker 2001. Permission to copy, use, modify, sell -// and distribute this software is granted provided this copyright -// notice appears in all copies. This software is provided "as is" without -// express or implied warranty, and with no claim as to its suitability for -// any purpose. - -// See http://www.boost.org for most recent version including documentation. - -// Revision History -// 29 Aug 2001 Initial Version (Daryle Walker) - -#define BOOST_INCLUDE_MAIN -#includeAll of the contents of <boost/call_traits.hpp> are -defined inside namespace boost.
- -The template class call_traits<T> encapsulates the -"best" method to pass a parameter of some type T to or -from a function, and consists of a collection of typedefs defined -as in the table below. The purpose of call_traits is to ensure -that problems like "references to references" -never occur, and that parameters are passed in the most efficient -manner possible (see examples). In each -case if your existing practice is to use the type defined on the -left, then replace it with the call_traits defined type on the -right.
- -Note that for compilers that do not support either partial -specialization or member templates, no benefit will occur from -using call_traits: the call_traits defined types will always be -the same as the existing practice in this case. In addition if -only member templates and not partial template specialisation is -support by the compiler (for example Visual C++ 6) then -call_traits can not be used with array types (although it can be -used to solve the reference to reference problem).
- -Existing practice - |
- call_traits equivalent - |
- Description - |
- Notes - |
-
T |
-
|
- Defines a type that - represents the "value" of type T. Use this for - functions that return by value, or possibly for stored - values of type T. | -2 - |
-
T& |
-
|
- Defines a type that - represents a reference to type T. Use for functions that - would normally return a T&. | -1 - |
-
const
- T& |
-
|
- Defines a type that - represents a constant reference to type T. Use for - functions that would normally return a const T&. | -1 - |
-
const
- T& |
-
|
- Defines a type that - represents the "best" way to pass a parameter - of type T to a function. | -1,3 - |
-
Notes:
- -value_type
- as a "constant pointer to type" rather than an
- "array of type" (requires partial
- specialization). Note that if you are using value_type as
- a stored value then this will result in storing a "constant
- pointer to an array" rather than the array itself.
- This may or may not be a good thing depending upon what
- you actually need (in other words take care!).param_type
- is defined as T const
, instead of T
- const&
. This can improve the ability of the
- compiler to optimize loops in the body of the function if
- they depend upon the passed parameter, the semantics of
- the passed parameter is otherwise unchanged (requires
- partial specialization).- -
The following table defines which call_traits types can always -be copy-constructed from which other types, those entries marked -with a '?' are true only if and only if T is copy constructible:
- -- | To: - |
- ||||
From: | -T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
-
T | -? - |
- ? - |
- Y - |
- Y - |
- Y - |
-
value_type | -? - |
- ? - |
- N - |
- N - |
- Y - |
-
reference | -? - |
- ? - |
- Y - |
- Y - |
- Y - |
-
const_reference | -? - |
- N - |
- N - |
- Y - |
- Y - |
-
param_type | -? - |
- ? - |
- N - |
- N - |
- Y - |
-
- -
If T is an assignable type the following assignments are -possible:
- -- | To: - |
- ||||
From: | -T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
-
T | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
value_type | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
reference | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
const_reference | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
param_type | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
- -
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.
- -- | Call_traits type: - |
- ||||
Original type T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
- Applies to: - |
-
myclass - |
- myclass - |
- myclass& - |
- const - myclass& - |
- myclass - const& - |
- All user - defined types. - |
-
int - |
- int - |
- int& - |
- const - int& - |
- int const - |
- All small - built-in types. - |
-
int* - |
- int* - |
- int*& - |
- int*const& - |
- int* const - |
- All - pointer types. - |
-
int& - |
- int& - |
- int& - |
- const - int& - |
- int& - |
- All - reference types. - |
-
const int& - |
- const - int& - |
- const - int& - |
- const - int& - |
- const - int& - |
- All - constant-references. - |
-
int[3] - |
- const int* - |
- int(&)[3] - |
- const int(&)[3] - |
- const int* - const - |
- All array - types. - |
-
const int[3] - |
- const int* - |
- const int(&)[3] - |
- const int(&)[3] - |
- const int* - const - |
- All - constant-array types. - |
-
- -
The following class is a trivial class that stores some type T -by value (see the call_traits_test.cpp -file), the aim is to illustrate how each of the available -call_traits typedefs may be used:
- -template <class T> -struct contained -{ - // define our typedefs first, arrays are stored by value - // so value_type is not the same as result_type: - typedef typename boost::call_traits<T>::param_type param_type; - typedef typename boost::call_traits<T>::reference reference; - typedef typename boost::call_traits<T>::const_reference const_reference; - typedef T value_type; - typedef typename boost::call_traits<T>::value_type result_type; - - // stored value: - value_type v_; - - // constructors: - contained() {} - contained(param_type p) : v_(p){} - // return byval: - result_type value() { return v_; } - // return by_ref: - reference get() { return v_; } - const_reference const_get()const { return v_; } - // pass value: - void call(param_type p){} - -};- -
Consider the definition of std::binder1st:
- -template <class Operation> -class binder1st : - public unary_function<typename Operation::second_argument_type, typename Operation::result_type> -{ -protected: - Operation op; - typename Operation::first_argument_type value; -public: - binder1st(const Operation& x, const typename Operation::first_argument_type& y); - typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const; -};- -
Now consider what happens in the relatively common case that
-the functor takes its second argument as a reference, that
-implies that Operation::second_argument_type
is a
-reference type, operator()
will now end up taking a
-reference to a reference as an argument, and that is not
-currently legal. The solution here is to modify operator()
-to use call_traits:
typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;- -
Now in the case that Operation::second_argument_type
-is a reference type, the argument is passed as a reference, and
-the no "reference to reference" occurs.
If we pass the name of an array as one (or both) arguments to std::make_pair
,
-then template argument deduction deduces the passed parameter as
-"const reference to array of T", this also applies to
-string literals (which are really array literals). Consequently
-instead of returning a pair of pointers, it tries to return a
-pair of arrays, and since an array type is not copy-constructible
-the code fails to compile. One solution is to explicitly cast the
-arguments to make_pair to pointers, but call_traits provides a
-better (i.e. automatic) solution (and one that works safely even
-in generic code where the cast might do the wrong thing):
template <class T1, class T2> -std::pair< - typename boost::call_traits<T1>::value_type, - typename boost::call_traits<T2>::value_type> - make_pair(const T1& t1, const T2& t2) -{ - return std::pair< - typename boost::call_traits<T1>::value_type, - typename boost::call_traits<T2>::value_type>(t1, t2); -}- -
Here, the deduced argument types will be automatically -degraded to pointers if the deduced types are arrays, similar -situations occur in the standard binders and adapters: in -principle in any function that "wraps" a temporary -whose type is deduced. Note that the function arguments to -make_pair are not expressed in terms of call_traits: doing so -would prevent template argument deduction from functioning.
- -The call_traits template will "optimize" the passing -of a small built-in type as a function parameter, this mainly has -an effect when the parameter is used within a loop body. In the -following example (see algo_opt_examples.cpp), -a version of std::fill is optimized in two ways: if the type -passed is a single byte built-in type then std::memset is used to -effect the fill, otherwise a conventional C++ implemention is -used, but with the passed parameter "optimized" using -call_traits:
- -namespace detail{ - -template <bool opt> -struct filler -{ - template <typename I, typename T> - static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val); - { - while(first != last) - { - *first = val; - ++first; - } - } -}; - -template <> -struct filler<true> -{ - template <typename I, typename T> - static void do_fill(I first, I last, T val) - { - memset(first, val, last-first); - } -}; - -} - -template <class I, class T> -inline void fill(I first, I last, const T& val) -{ - enum{ can_opt = boost::is_pointer<I>::value - && boost::is_arithmetic<T>::value - && (sizeof(T) == 1) }; - typedef detail::filler<can_opt> filler_t; - filler_t::template do_fill<I,T>(first, last, val); -}- -
Footnote: the reason that this is "optimal" for -small built-in types is that with the value passed as "T -const" instead of "const T&" the compiler is -able to tell both that the value is constant and that it is free -of aliases. With this information the compiler is able to cache -the passed value in a register, unroll the loop, or use -explicitly parallel instructions: if any of these are supported. -Exactly how much mileage you will get from this depends upon your -compiler - we could really use some accurate benchmarking -software as part of boost for cases like this.
- -Note that the function arguments to fill are not expressed in -terms of call_traits: doing so would prevent template argument -deduction from functioning. Instead fill acts as a "thin -wrapper" that is there to perform template argument -deduction, the compiler will optimise away the call to fill all -together, replacing it with the call to filler<>::do_fill, -which does use call_traits.
- -The following notes are intended to briefly describe the -rational behind choices made in call_traits.
- -All user-defined types follow "existing practice" -and need no comment.
- -Small built-in types (what the standard calls fundamental -types [3.9.1]) differ from existing practice only in the param_type -typedef. In this case passing "T const" is compatible -with existing practice, but may improve performance in some cases -(see Example 4), in any case this should never -be any worse than existing practice.
- -Pointers follow the same rational as small built-in types.
- -For reference types the rational follows Example -2 - references to references are not allowed, so the -call_traits members must be defined such that these problems do -not occur. There is a proposal to modify the language such that -"a reference to a reference is a reference" (issue #106, -submitted by Bjarne Stroustrup), call_traits<T>::value_type -and call_traits<T>::param_type both provide the same effect -as that proposal, without the need for a language change (in -other words it's a workaround).
- -For array types, a function that takes an array as an argument -will degrade the array type to a pointer type: this means that -the type of the actual parameter is different from its declared -type, something that can cause endless problems in template code -that relies on the declared type of a parameter. For example:
- -template <class T> -struct A -{ - void foo(T t); -};- -
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:
- -template <class T> -void A<T>::foo(T t) -{ - T dup(t); // doesn't compile for case that T is an array. -}- -
By using call_traits the degradation from array to pointer is -explicit, and the type of the parameter is the same as it's -declared type:
- -template <class T> -struct A -{ - void foo(typename call_traits<T>::value_type t); -}; - -template <class T> -void A<T>::foo(typename call_traits<T>::value_type t) -{ - typename call_traits<T>::value_type dup(t); // OK even if T is an array type. -}- -
For value_type (return by value), again only a pointer may be -returned, not a copy of the whole array, and again call_traits -makes the degradation explicit. The value_type member is useful -whenever an array must be explicitly degraded to a pointer - Example 3 provides the test case (Footnote: the -array specialisation for call_traits is the least well understood -of all the call_traits specialisations, if the given semantics -cause specific problems for you, or don't solve a particular -array-related problem, then I would be interested to hear about -it. Most people though will probably never need to use this -specialisation).
- -Revised 01 September 2000
- -© 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.
- -Based on contributions by Steve Cleary, Beman Dawes, Howard -Hinnant and John Maddock.
- -Maintained by John -Maddock, the latest version of this file can be found at www.boost.org, and the boost -discussion list at www.yahoogroups.com/list/boost.
- -.
- -- -
- - diff --git a/call_traits_test.cpp b/call_traits_test.cpp deleted file mode 100644 index afeb285..0000000 --- a/call_traits_test.cpp +++ /dev/null @@ -1,414 +0,0 @@ - // boost::compressed_pair test program - - // (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and - // distribute this software is granted provided this copyright notice appears - // in all copies. This software is provided "as is" without express or implied - // warranty, and with no claim as to its suitability for any purpose. - -// standalone test program for
All of the contents of <boost/compressed_pair.hpp> are -defined inside namespace boost.
- -The class compressed pair is very similar to std::pair, but if -either of the template arguments are empty classes, then the -"empty base-class optimisation" is applied to compress -the size of the pair.
- -template <class T1, class T2> -class compressed_pair -{ -public: - typedef T1 first_type; - typedef T2 second_type; - typedef typename call_traits<first_type>::param_type first_param_type; - typedef typename call_traits<second_type>::param_type second_param_type; - typedef typename call_traits<first_type>::reference first_reference; - typedef typename call_traits<second_type>::reference second_reference; - typedef typename call_traits<first_type>::const_reference first_const_reference; - typedef typename call_traits<second_type>::const_reference second_const_reference; - - compressed_pair() : base() {} - compressed_pair(first_param_type x, second_param_type y); - explicit compressed_pair(first_param_type x); - explicit compressed_pair(second_param_type y); - - compressed_pair& operator=(const compressed_pair&); - - first_reference first(); - first_const_reference first() const; - - second_reference second(); - second_const_reference second() const; - - void swap(compressed_pair& y); -};- -
The two members of the pair can be accessed using the member -functions first() and second(). Note that not all member -functions can be instantiated for all template parameter types. -In particular compressed_pair can be instantiated for reference -and array types, however in these cases the range of constructors -that can be used are limited. If types T1 and T2 are the same -type, then there is only one version of the single-argument -constructor, and this constructor initialises both values in the -pair to the passed value.
- -Note that compressed_pair can not be instantiated if either of -the template arguments is a union type, unless there is compiler -support for boost::is_union, or if boost::is_union is specialised -for the union type.
- -Finally, a word of caution for Visual C++ 6 users: if either -argument is an empty type, then assigning to that member will -produce memory corruption, unless the empty type has a "do -nothing" assignment operator defined. This is due to a bug -in the way VC6 generates implicit assignment operators.
- -Revised 08 May 2001
- -© 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.
- -Based on contributions by Steve Cleary, Beman Dawes, Howard -Hinnant and John Maddock.
- -Maintained by John -Maddock, the latest version of this file can be found at www.boost.org, and the boost -discussion list at www.yahoogroups.com/list/boost.
- -- - diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp deleted file mode 100644 index 25a2cb4..0000000 --- a/compressed_pair_test.cpp +++ /dev/null @@ -1,401 +0,0 @@ - // boost::compressed_pair test program - - // (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and - // distribute this software is granted provided this copyright notice appears - // in all copies. This software is provided "as is" without express or implied - // warranty, and with no claim as to its suitability for any purpose. - -// standalone test program for
-How would you fill up a vector with the numbers zero -through one hundred using std::copy()? The -only iterator operation missing from builtin integer types is an -operator*() 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 Incrementable (see type requirements below). The -following pseudo-code shows the general idea of how the -counting iterator is implemented. -
- -- // inside a hypothetical counting_iterator class... - typedef Incrementable value_type; - value_type counting_iterator::operator*() const { - return this->base; // no dereference! - } -- -All of the other operators of the counting iterator behave in the same -fashion as the Incrementable base type. - -
-namespace boost { - template <class Incrementable> - struct counting_iterator_traits; - - template <class Incrementable> - struct counting_iterator_generator; - - template <class Incrementable> - typename counting_iterator_generator<Incrementable>::type - make_counting_iterator(Incrementable x); -} -- -
-template <class Incrementable> -class counting_iterator_generator -{ -public: - typedef iterator_adaptor<...> type; -}; -- -
-#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... --The output from this part is: -
-counting from 0 to 4: -0 1 2 3 -- -
Parameter | Description | -
---|---|
Incrementable | -The type being wrapped by the adaptor. | -
-Furthermore, if you wish to create a counting iterator that is a Forward -Iterator, then the following expressions must be valid: -
-Incrementable i, j; -++i // pre-increment -i == j // operator equal --If you wish to create a counting iterator that is a -Bidirectional Iterator, then pre-decrement is also required: -
---i --If you wish to create a counting iterator that is a Random -Access Iterator, then these additional expressions are also required: -
-counting_iterator_traits<Incrementable>::difference_type n; -i += n -n = i - j -i < j -- - - -
-counting_iterator_generator::type(const Incrementable& i) -- -
-
- - -
-template <class Incrementable> -typename counting_iterator_generator<Incrementable>::type -make_counting_iterator(Incrementable base); -- -An object -generator function that provides a convenient way to create counting -iterators.
- - - -
- // 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... --The output from this part is: -
-counting from -5 to 4: --5 -4 -3 -2 -1 0 1 2 3 4 -- -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 indirect iterator adaptor to print -out the number in the array by accessing the numbers through the array -of pointers. - -
- // 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; --The output is: -
-indirectly printing out the numbers from 0 to 7 -0 1 2 3 4 5 6 -- -
The following pseudocode describes how the counting_iterator_traits are determined: - -
-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 next-larger-signed-type-or-intmax_t 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; - } -}; -- -
The italicized sections above are implementation details, but it is important -to know that the difference_type 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 std::numeric_limits -implementation, the difference_type for any variable-length signed -integer type T is T itself. - -
Revised 19 Aug 2001
-© 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.
- - - - - - - diff --git a/counting_iterator_example.cpp b/counting_iterator_example.cpp deleted file mode 100644 index 9513c06..0000000 --- a/counting_iterator_example.cpp +++ /dev/null @@ -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