mirror of
https://github.com/boostorg/utility.git
synced 2025-10-06 22:10:54 +02:00
Compare commits
21 Commits
svn-branch
...
boost-1.25
Author | SHA1 | Date | |
---|---|---|---|
|
4d452a1170 | ||
|
117720a8bc | ||
|
a6f6c3613a | ||
|
7914f5b931 | ||
|
a1add0a6f6 | ||
|
c032b337c4 | ||
|
ec363261ae | ||
|
97cde2183d | ||
|
7f43c682db | ||
|
0c9eee3c6b | ||
|
3b1afa3ba6 | ||
|
93e6a75125 | ||
|
52f8a7c0ca | ||
|
55bfeb646f | ||
|
75c9dd3be1 | ||
|
6392e2788f | ||
|
6a97f3f9ba | ||
|
6e5f52e279 | ||
|
7f92bed902 | ||
|
d68a11cc42 | ||
|
328a81e194 |
@@ -85,7 +85,7 @@ Once that is done we can drop Multi-Pass Input Iterator.
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=file:///c:/boost/site/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||
<a HREF="../../people/jeremy_siek.htm">Jeremy Siek</a>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||
</TD></TR></TABLE>
|
||||
|
||||
</BODY>
|
||||
|
341
base_from_member.html
Normal file
341
base_from_member.html
Normal file
@@ -0,0 +1,341 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Boost: Base-from-Member Idiom Documentation</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="white" link="blue" text="black" vlink="purple" alink="red">
|
||||
<h1><img src="../../c++boost.gif" alt="C++ Boost" align="middle"
|
||||
width="277" height="86">Base-from-Member Idiom</h1>
|
||||
|
||||
<p>The class template <code>boost::base_from_member</code> provides
|
||||
a workaround for a class that needs to initialize a base class with a
|
||||
member. The class template is in <cite><a
|
||||
href="../../boost/utility/base_from_member.hpp">boost/utility/base_from_member.hpp</a></cite>
|
||||
which is included in <i><a href="../../boost/utility.hpp">boost/utility.hpp</a></i>.
|
||||
The class template is forward declared in <i><a href="../../boost/utility_fwd.hpp">boost/utility_fwd.hpp</a></i>.</p>
|
||||
|
||||
<p>There is test/example code in <cite><a
|
||||
href="base_from_member_test.cpp">base_from_member_test.cpp</a></cite>.</p>
|
||||
|
||||
<h2><a name="contents">Contents</a></h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#contents">Contents</a></li>
|
||||
<li><a href="#rationale">Rationale</a></li>
|
||||
<li><a href="#synopsis">Synopsis</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#credits">Credits</a>
|
||||
<ul>
|
||||
<li><a href="#contributors">Contributors</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="rationale">Rationale</a></h2>
|
||||
|
||||
<p>When developing a class, sometimes a base class needs to be
|
||||
initialized with a member of the current class. As a naïve
|
||||
example:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
#include <streambuf> <i>// for std::streambuf</i>
|
||||
#include <ostream> <i>// for std::ostream</i>
|
||||
|
||||
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 )
|
||||
{}
|
||||
//...
|
||||
};
|
||||
</pre></blockquote>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>A custom base class can be made for this idiom:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
#include <streambuf> <i>// for std::streambuf</i>
|
||||
#include <ostream> <i>// for std::ostream</i>
|
||||
|
||||
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 )
|
||||
{}
|
||||
//...
|
||||
};
|
||||
</pre></blockquote>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2><a name="synopsis">Synopsis</a></h2>
|
||||
|
||||
<blockquote><pre>
|
||||
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 );
|
||||
};
|
||||
</pre></blockquote>
|
||||
|
||||
<p>The class template has a first template parameter
|
||||
<var>MemberType</var> representing the type of the based-member.
|
||||
It has a last template parameter <var>UniqueID</var>, that is an
|
||||
<code>int</code>, 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 <var>member</var> that the derived class can use
|
||||
for later base classes (or itself).</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2><a name="usage">Usage</a></h2>
|
||||
|
||||
<p>With the starting example, the <code>fdoutbuf</code> sub-object needs
|
||||
to be encapsulated in a base class that is inheirited before
|
||||
<code>std::ostream</code>.</p>
|
||||
|
||||
<blockquote><pre>
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
#include <streambuf> <i>// for std::streambuf</i>
|
||||
#include <ostream> <i>// for std::ostream</i>
|
||||
|
||||
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 )
|
||||
{}
|
||||
//...
|
||||
};
|
||||
</pre></blockquote>
|
||||
|
||||
<p>The base-from-member idiom is an implementation detail, so it
|
||||
should not be visible to the clients (or any derived classes) of
|
||||
<code>fdostream</code>. Due to the initialization order, the
|
||||
<code>fdoutbuf</code> sub-object will get initialized before the
|
||||
<code>std::ostream</code> sub-object does, making the former
|
||||
sub-object safe to use in the latter sub-object's construction. Since the
|
||||
<code>fdoutbuf</code> 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.</p>
|
||||
|
||||
<h2><a name="example">Example</a></h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<blockquote><pre>
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
#include <cstddef> <i>// for NULL</i>
|
||||
|
||||
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 )
|
||||
{
|
||||
//...
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
<p>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 <code>typedef</code>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 <code>an_int boost::base_from_member<an_int,
|
||||
0> :: *</code>) instead of a pointer to the member (having a type of
|
||||
<code>an_int *</code>). The new problem is fixed by qualifying the
|
||||
sub-object with "<code>this-></code>," and is needed just
|
||||
for pointers, and not for references or values.</p>
|
||||
|
||||
<p>There are some argument conversions in the initialization. The
|
||||
constructor argument for <code>pbase0_type</code> is converted from
|
||||
<code>double</code> to <code>float</code>. The first constructor
|
||||
argument for <code>pbase2_type</code> is converted from <code>int</code>
|
||||
to <code>double</code>. The second constructor argument for
|
||||
<code>pbase3_type</code> 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 <code>switcher</code>'s constructor.</p>
|
||||
|
||||
<h2><a name="credits">Credits</a></h2>
|
||||
|
||||
<h3><a name="contributors">Contributors</a></h3>
|
||||
|
||||
<dl>
|
||||
<dt><a href="../../people/ed_brey.htm">Ed Brey</a>
|
||||
<dd>Suggested some interface changes.
|
||||
|
||||
<dt>Ron Klatchko (<a href="mailto:ron@crl.com">ron@crl.com</a>)
|
||||
<dd>Invented the idiom of how to use a class member for initializing
|
||||
a base class.
|
||||
|
||||
<dt><a href="../../people/dietmar_kuehl.htm">Dietmar Kuehl</a>
|
||||
<dd>Popularized the base-from-member idiom in his
|
||||
<a href="http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/">IOStream
|
||||
example classes</a>.
|
||||
|
||||
<dt><a href="../../people/daryle_walker.html">Daryle Walker</a>
|
||||
<dd>Started the library. Contributed the test file <cite><a
|
||||
href="base_from_member_test.cpp">base_from_member_test.cpp</a></cite>.
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised: 22 August 2001</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
597
base_from_member_test.cpp
Normal file
597
base_from_member_test.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
// 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
|
||||
#include <boost/test/test_tools.hpp> // for BOOST_TEST, main
|
||||
|
||||
#include <boost/config.hpp> // for BOOST_NO_MEMBER_TEMPLATES
|
||||
#include <boost/cstdlib.hpp> // for boost::exit_success
|
||||
#include <boost/utility.hpp> // for boost::noncopyable
|
||||
|
||||
#include <boost/utility/base_from_member.hpp> // for boost::base_from_member
|
||||
|
||||
#include <functional> // for std::binary_function, std::less
|
||||
#include <iostream> // for std::cout (std::ostream, std::endl indirectly)
|
||||
#include <set> // for std::set
|
||||
#include <typeinfo> // for std::type_info
|
||||
#include <utility> // for std::pair, std::make_pair
|
||||
#include <vector> // for std::vector
|
||||
|
||||
|
||||
// Control if extra information is printed
|
||||
#ifndef CONTROL_EXTRA_PRINTING
|
||||
#define CONTROL_EXTRA_PRINTING 1
|
||||
#endif
|
||||
|
||||
|
||||
// A (sub)object can be identified by its memory location and its type.
|
||||
// Both are needed since an object can start at the same place as its
|
||||
// first base class subobject and/or contained subobject.
|
||||
typedef std::pair< void *, std::type_info const * > object_id;
|
||||
|
||||
// Object IDs need to be printed
|
||||
std::ostream & operator <<( std::ostream &os, object_id const &oi );
|
||||
|
||||
// A way to generate an object ID
|
||||
template < typename T >
|
||||
object_id identify( T &obj );
|
||||
|
||||
// A custom comparison type is needed
|
||||
struct object_id_compare
|
||||
: std::binary_function<object_id, object_id, bool>
|
||||
{
|
||||
bool operator ()( object_id const &a, object_id const &b ) const;
|
||||
|
||||
}; // object_id_compare
|
||||
|
||||
// A singleton of this type coordinates the acknowledgements
|
||||
// of objects being created and used.
|
||||
class object_registrar
|
||||
: boost::noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATES
|
||||
template < typename T >
|
||||
void register_object( T &obj )
|
||||
{ this->register_object_imp( identify(obj) ); }
|
||||
template < typename T, typename U >
|
||||
void register_use( T &owner, U &owned )
|
||||
{ this->register_use_imp( identify(owner), identify(owned) ); }
|
||||
template < typename T, typename U >
|
||||
void unregister_use( T &owner, U &owned )
|
||||
{ this->unregister_use_imp( identify(owner), identify(owned) ); }
|
||||
template < typename T >
|
||||
void unregister_object( T &obj )
|
||||
{ this->unregister_object_imp( identify(obj) ); }
|
||||
#endif
|
||||
|
||||
void register_object_imp( object_id obj );
|
||||
void register_use_imp( object_id owner, object_id owned );
|
||||
void unregister_use_imp( object_id owner, object_id owned );
|
||||
void unregister_object_imp( object_id obj );
|
||||
|
||||
typedef std::set<object_id, object_id_compare> set_type;
|
||||
|
||||
typedef std::vector<object_id> error_record_type;
|
||||
typedef std::vector< std::pair<object_id, object_id> > error_pair_type;
|
||||
|
||||
set_type db_;
|
||||
|
||||
error_pair_type defrauders_in_, defrauders_out_;
|
||||
error_record_type overeager_, overkilled_;
|
||||
|
||||
}; // object_registrar
|
||||
|
||||
// A sample type to be used by containing types
|
||||
class base_or_member
|
||||
{
|
||||
public:
|
||||
explicit base_or_member( int x = 1, double y = -0.25 );
|
||||
~base_or_member();
|
||||
|
||||
}; // base_or_member
|
||||
|
||||
// A sample type that uses base_or_member, used
|
||||
// as a base for the main demonstration classes
|
||||
class base_class
|
||||
{
|
||||
public:
|
||||
explicit base_class( base_or_member &x, base_or_member *y = 0,
|
||||
base_or_member *z = 0 );
|
||||
|
||||
~base_class();
|
||||
|
||||
private:
|
||||
base_or_member *x_, *y_, *z_;
|
||||
|
||||
}; // base_class
|
||||
|
||||
// This bad class demonstrates the direct method of a base class needing
|
||||
// to be initialized by a member. This is improper since the member
|
||||
// isn't initialized until after the base class.
|
||||
class bad_class
|
||||
: public base_class
|
||||
{
|
||||
public:
|
||||
bad_class();
|
||||
~bad_class();
|
||||
|
||||
private:
|
||||
base_or_member x_;
|
||||
|
||||
}; // bad_class
|
||||
|
||||
// The first good class demonstrates the correct way to initialize a
|
||||
// base class with a member. The member is changed to another base
|
||||
// class, one that is initialized before the base that needs it.
|
||||
class good_class_1
|
||||
: private boost::base_from_member<base_or_member>
|
||||
, public base_class
|
||||
{
|
||||
typedef boost::base_from_member<base_or_member> pbase_type;
|
||||
typedef base_class base_type;
|
||||
|
||||
public:
|
||||
good_class_1();
|
||||
~good_class_1();
|
||||
|
||||
}; // good_class_1
|
||||
|
||||
// The second good class also demonstrates the correct way to initialize
|
||||
// base classes with other subobjects. This class uses the other helpers
|
||||
// in the library, and shows the technique of using two base subobjects
|
||||
// of the "same" type.
|
||||
class good_class_2
|
||||
: private boost::base_from_member<base_or_member, 0>
|
||||
, private boost::base_from_member<base_or_member, 1>
|
||||
, private boost::base_from_member<base_or_member, 2>
|
||||
, public base_class
|
||||
{
|
||||
typedef boost::base_from_member<base_or_member, 0> pbase_type0;
|
||||
typedef boost::base_from_member<base_or_member, 1> pbase_type1;
|
||||
typedef boost::base_from_member<base_or_member, 2> pbase_type2;
|
||||
typedef base_class base_type;
|
||||
|
||||
public:
|
||||
good_class_2();
|
||||
~good_class_2();
|
||||
|
||||
}; // good_class_2
|
||||
|
||||
// Declare/define the single object registrar
|
||||
object_registrar obj_reg;
|
||||
|
||||
|
||||
// Main functionality
|
||||
int
|
||||
test_main( int , char * [] )
|
||||
{
|
||||
BOOST_TEST( obj_reg.db_.empty() );
|
||||
BOOST_TEST( obj_reg.defrauders_in_.empty() );
|
||||
BOOST_TEST( obj_reg.defrauders_out_.empty() );
|
||||
BOOST_TEST( obj_reg.overeager_.empty() );
|
||||
BOOST_TEST( obj_reg.overkilled_.empty() );
|
||||
|
||||
// Make a separate block to examine pre- and post-effects
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
bad_class bc;
|
||||
BOOST_TEST( obj_reg.db_.size() == 3 );
|
||||
BOOST_TEST( obj_reg.defrauders_in_.size() == 1 );
|
||||
|
||||
good_class_1 gc1;
|
||||
BOOST_TEST( obj_reg.db_.size() == 6 );
|
||||
BOOST_TEST( obj_reg.defrauders_in_.size() == 1 );
|
||||
|
||||
good_class_2 gc2;
|
||||
BOOST_TEST( obj_reg.db_.size() == 11 );
|
||||
BOOST_TEST( obj_reg.defrauders_in_.size() == 1 );
|
||||
|
||||
BOOST_TEST( obj_reg.defrauders_out_.empty() );
|
||||
BOOST_TEST( obj_reg.overeager_.empty() );
|
||||
BOOST_TEST( obj_reg.overkilled_.empty() );
|
||||
|
||||
// Getting the addresses of the objects ensure
|
||||
// that they're used, and not optimized away.
|
||||
cout << "Object 'bc' is at " << &bc << '.' << endl;
|
||||
cout << "Object 'gc1' is at " << &gc1 << '.' << endl;
|
||||
cout << "Object 'gc2' is at " << &gc2 << '.' << endl;
|
||||
}
|
||||
|
||||
BOOST_TEST( obj_reg.db_.empty() );
|
||||
BOOST_TEST( obj_reg.defrauders_in_.size() == 1 );
|
||||
BOOST_TEST( obj_reg.defrauders_out_.size() == 1 );
|
||||
BOOST_TEST( obj_reg.overeager_.empty() );
|
||||
BOOST_TEST( obj_reg.overkilled_.empty() );
|
||||
|
||||
return boost::exit_success;
|
||||
}
|
||||
|
||||
|
||||
// Print an object's ID
|
||||
std::ostream &
|
||||
operator <<
|
||||
(
|
||||
std::ostream & os,
|
||||
object_id const & oi
|
||||
)
|
||||
{
|
||||
// I had an std::ostringstream to help, but I did not need it since
|
||||
// the program never screws around with formatting. Worse, using
|
||||
// std::ostringstream is an issue with some compilers.
|
||||
|
||||
return os << '[' << ( oi.second ? oi.second->name() : "NOTHING" )
|
||||
<< " at " << oi.first << ']';
|
||||
}
|
||||
|
||||
// Get an object ID given an object
|
||||
template < typename T >
|
||||
inline
|
||||
object_id
|
||||
identify
|
||||
(
|
||||
T & obj
|
||||
)
|
||||
{
|
||||
return std::make_pair( static_cast<void *>(&obj), &(typeid( obj )) );
|
||||
}
|
||||
|
||||
// Compare two object IDs
|
||||
bool
|
||||
object_id_compare::operator ()
|
||||
(
|
||||
object_id const & a,
|
||||
object_id const & b
|
||||
) const
|
||||
{
|
||||
std::less<void *> vp_cmp;
|
||||
if ( vp_cmp(a.first, b.first) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ( vp_cmp(b.first, a.first) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// object pointers are equal, compare the types
|
||||
if ( a.second == b.second )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if ( !a.second )
|
||||
{
|
||||
return true; // NULL preceeds anything else
|
||||
}
|
||||
else if ( !b.second )
|
||||
{
|
||||
return false; // NULL preceeds anything else
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.second->before( *b.second );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let an object register its existence
|
||||
void
|
||||
object_registrar::register_object_imp
|
||||
(
|
||||
object_id obj
|
||||
)
|
||||
{
|
||||
if ( db_.count(obj) <= 0 )
|
||||
{
|
||||
db_.insert( obj );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Registered " << obj << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
overeager_.push_back( obj );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Attempted to register a non-existant " << obj
|
||||
<< '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Let an object register its use of another object
|
||||
void
|
||||
object_registrar::register_use_imp
|
||||
(
|
||||
object_id owner,
|
||||
object_id owned
|
||||
)
|
||||
{
|
||||
if ( db_.count(owned) > 0 )
|
||||
{
|
||||
// We don't care to record usage registrations
|
||||
}
|
||||
else
|
||||
{
|
||||
defrauders_in_.push_back( std::make_pair(owner, owned) );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Attempted to own a non-existant " << owned
|
||||
<< " by " << owner << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Let an object un-register its use of another object
|
||||
void
|
||||
object_registrar::unregister_use_imp
|
||||
(
|
||||
object_id owner,
|
||||
object_id owned
|
||||
)
|
||||
{
|
||||
if ( db_.count(owned) > 0 )
|
||||
{
|
||||
// We don't care to record usage un-registrations
|
||||
}
|
||||
else
|
||||
{
|
||||
defrauders_out_.push_back( std::make_pair(owner, owned) );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Attempted to disown a non-existant " << owned
|
||||
<< " by " << owner << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Let an object un-register its existence
|
||||
void
|
||||
object_registrar::unregister_object_imp
|
||||
(
|
||||
object_id obj
|
||||
)
|
||||
{
|
||||
set_type::iterator const i = db_.find( obj );
|
||||
|
||||
if ( i != db_.end() )
|
||||
{
|
||||
db_.erase( i );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Unregistered " << obj << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
overkilled_.push_back( obj );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "Attempted to unregister a non-existant " << obj
|
||||
<< '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Macros to abstract the registration of objects
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATES
|
||||
#define PRIVATE_REGISTER_BIRTH(o) obj_reg.register_object( (o) )
|
||||
#define PRIVATE_REGISTER_DEATH(o) obj_reg.unregister_object( (o) )
|
||||
#define PRIVATE_REGISTER_USE(o, w) obj_reg.register_use( (o), (w) )
|
||||
#define PRIVATE_UNREGISTER_USE(o, w) obj_reg.unregister_use( (o), (w) )
|
||||
#else
|
||||
#define PRIVATE_REGISTER_BIRTH(o) obj_reg.register_object_imp( \
|
||||
identify((o)) )
|
||||
#define PRIVATE_REGISTER_DEATH(o) obj_reg.unregister_object_imp( \
|
||||
identify((o)) )
|
||||
#define PRIVATE_REGISTER_USE(o, w) obj_reg.register_use_imp( identify((o)), \
|
||||
identify((w)) )
|
||||
#define PRIVATE_UNREGISTER_USE(o, w) obj_reg.unregister_use_imp( \
|
||||
identify((o)), identify((w)) )
|
||||
#endif
|
||||
|
||||
// Create a base_or_member, with arguments to simulate member initializations
|
||||
base_or_member::base_or_member
|
||||
(
|
||||
int x, // = 1
|
||||
double y // = -0.25
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_BIRTH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy x-factor is " << x << " and my y-factor is " << y
|
||||
<< '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy a base_or_member
|
||||
inline
|
||||
base_or_member::~base_or_member
|
||||
(
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_DEATH( *this );
|
||||
}
|
||||
|
||||
// Create a base_class, registering any objects used
|
||||
base_class::base_class
|
||||
(
|
||||
base_or_member & x,
|
||||
base_or_member * y, // = 0
|
||||
base_or_member * z // = 0
|
||||
)
|
||||
: x_( &x ), y_( y ), z_( z )
|
||||
{
|
||||
PRIVATE_REGISTER_BIRTH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy x-factor is " << x_;
|
||||
#endif
|
||||
|
||||
PRIVATE_REGISTER_USE( *this, *x_ );
|
||||
|
||||
if ( y_ )
|
||||
{
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << ", my y-factor is " << y_;
|
||||
#endif
|
||||
|
||||
PRIVATE_REGISTER_USE( *this, *y_ );
|
||||
}
|
||||
|
||||
if ( z_ )
|
||||
{
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << ", my z-factor is " << z_;
|
||||
#endif
|
||||
|
||||
PRIVATE_REGISTER_USE( *this, *z_ );
|
||||
}
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy a base_class, unregistering the objects it uses
|
||||
base_class::~base_class
|
||||
(
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_DEATH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy x-factor was " << x_;
|
||||
#endif
|
||||
|
||||
PRIVATE_UNREGISTER_USE( *this, *x_ );
|
||||
|
||||
if ( y_ )
|
||||
{
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << ", my y-factor was " << y_;
|
||||
#endif
|
||||
|
||||
PRIVATE_UNREGISTER_USE( *this, *y_ );
|
||||
}
|
||||
|
||||
if ( z_ )
|
||||
{
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << ", my z-factor was " << z_;
|
||||
#endif
|
||||
|
||||
PRIVATE_UNREGISTER_USE( *this, *z_ );
|
||||
}
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a bad_class, noting the improper construction order
|
||||
bad_class::bad_class
|
||||
(
|
||||
)
|
||||
: x_( -7, 16.75 ), base_class( x_ ) // this order doesn't matter
|
||||
{
|
||||
PRIVATE_REGISTER_BIRTH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factor is at " << &x_
|
||||
<< " and my base is at " << static_cast<base_class *>(this) << '.'
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy a bad_class, noting the improper destruction order
|
||||
bad_class::~bad_class
|
||||
(
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_DEATH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factor was at " << &x_
|
||||
<< " and my base was at " << static_cast<base_class *>(this)
|
||||
<< '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a good_class_1, noting the proper construction order
|
||||
good_class_1::good_class_1
|
||||
(
|
||||
)
|
||||
: pbase_type( 8 ), base_type( member )
|
||||
{
|
||||
PRIVATE_REGISTER_BIRTH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factor is at " << &member
|
||||
<< " and my base is at " << static_cast<base_class *>(this) << '.'
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy a good_class_1, noting the proper destruction order
|
||||
good_class_1::~good_class_1
|
||||
(
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_DEATH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factor was at " << &member
|
||||
<< " and my base was at " << static_cast<base_class *>(this)
|
||||
<< '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a good_class_2, noting the proper construction order
|
||||
good_class_2::good_class_2
|
||||
(
|
||||
)
|
||||
: pbase_type0(), pbase_type1(-16, 0.125), pbase_type2(2, -3)
|
||||
, base_type( pbase_type1::member, &this->pbase_type0::member,
|
||||
&this->pbase_type2::member )
|
||||
{
|
||||
PRIVATE_REGISTER_BIRTH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factors are at " << &this->pbase_type0::member
|
||||
<< ", " << &this->pbase_type1::member << ", "
|
||||
<< &this->pbase_type2::member << ", and my base is at "
|
||||
<< static_cast<base_class *>(this) << '.' << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destroy a good_class_2, noting the proper destruction order
|
||||
good_class_2::~good_class_2
|
||||
(
|
||||
)
|
||||
{
|
||||
PRIVATE_REGISTER_DEATH( *this );
|
||||
|
||||
#if CONTROL_EXTRA_PRINTING
|
||||
std::cout << "\tMy factors were at " << &this->pbase_type0::member
|
||||
<< ", " << &this->pbase_type1::member << ", "
|
||||
<< &this->pbase_type2::member << ", and my base was at "
|
||||
<< static_cast<base_class *>(this) << '.' << std::endl;
|
||||
#endif
|
||||
}
|
@@ -17,6 +17,10 @@
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
#include <boost/type_traits/type_traits_test.hpp>
|
||||
|
||||
// a way prevent warnings for unused variables
|
||||
template<class T> inline void unused_variable(const T&) {}
|
||||
|
||||
//
|
||||
// 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:
|
||||
@@ -44,7 +48,7 @@ struct contained
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
// pass value:
|
||||
void call(param_type p){}
|
||||
void call(param_type){}
|
||||
|
||||
};
|
||||
|
||||
@@ -69,7 +73,7 @@ struct contained<T[N]>
|
||||
// return by_ref:
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
void call(param_type p){}
|
||||
void call(param_type){}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -181,6 +185,12 @@ struct comparible_UDT
|
||||
{
|
||||
int i_;
|
||||
comparible_UDT() : i_(2){}
|
||||
comparible_UDT(const comparible_UDT& other) : i_(other.i_){}
|
||||
comparible_UDT& operator=(const comparible_UDT& other)
|
||||
{
|
||||
i_ = other.i_;
|
||||
return *this;
|
||||
}
|
||||
bool operator == (const comparible_UDT& v){ return v.i_ == i_; }
|
||||
};
|
||||
|
||||
@@ -193,6 +203,7 @@ int main(int argc, char *argv[ ])
|
||||
int i = 2;
|
||||
c2(i);
|
||||
int* pi = &i;
|
||||
int a[2] = {1,2};
|
||||
#if (defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)) && !defined(__ICL)
|
||||
call_traits_checker<int*> c3;
|
||||
c3(pi);
|
||||
@@ -201,15 +212,14 @@ int main(int argc, char *argv[ ])
|
||||
call_traits_checker<const int&> c5;
|
||||
c5(i);
|
||||
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__MWERKS__)
|
||||
int a[2] = {1,2};
|
||||
call_traits_checker<int[2]> c6;
|
||||
c6(a);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
check_wrap(wrap(2), 2);
|
||||
const char ca[4] = "abc";
|
||||
// compiler can't deduce this for some reason:
|
||||
//const char ca[4] = "abc";
|
||||
//check_wrap(wrap(ca), ca);
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
check_wrap(wrap(a), a);
|
||||
@@ -312,6 +322,19 @@ void call_traits_test<T, isarray>::assert_construct(typename call_traits_test<T,
|
||||
param_type p2(v);
|
||||
param_type p3(r);
|
||||
param_type p4(p);
|
||||
|
||||
unused_variable(v2);
|
||||
unused_variable(v3);
|
||||
unused_variable(v4);
|
||||
unused_variable(r2);
|
||||
unused_variable(r3);
|
||||
unused_variable(cr2);
|
||||
unused_variable(cr3);
|
||||
unused_variable(cr4);
|
||||
unused_variable(cr5);
|
||||
unused_variable(p2);
|
||||
unused_variable(p3);
|
||||
unused_variable(p4);
|
||||
}
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template <typename T>
|
||||
@@ -348,6 +371,17 @@ void call_traits_test<T, true>::assert_construct(typename boost::call_traits<T>:
|
||||
param_type p2(v);
|
||||
param_type p3(r);
|
||||
param_type p4(p);
|
||||
|
||||
unused_variable(v2);
|
||||
unused_variable(v3);
|
||||
unused_variable(v4);
|
||||
unused_variable(v5);
|
||||
unused_variable(r2);
|
||||
unused_variable(cr2);
|
||||
unused_variable(cr3);
|
||||
unused_variable(p2);
|
||||
unused_variable(p3);
|
||||
unused_variable(p4);
|
||||
}
|
||||
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
//
|
||||
|
@@ -21,8 +21,8 @@ defined inside namespace boost.</p>
|
||||
|
||||
<p>The class compressed pair is very similar to std::pair, but if
|
||||
either of the template arguments are empty classes, then the
|
||||
"empty member optimisation" is applied to compress the
|
||||
size of the pair.</p>
|
||||
"empty base-class optimisation" is applied to compress
|
||||
the size of the pair.</p>
|
||||
|
||||
<pre>template <class T1, class T2>
|
||||
class compressed_pair
|
||||
|
@@ -199,7 +199,7 @@ struct compressed_pair_reference1_tester
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_reference1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
void compressed_pair_reference1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type, second_param_type)
|
||||
{
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// first param construct:
|
||||
@@ -225,7 +225,7 @@ struct compressed_pair_reference2_tester
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_reference2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
void compressed_pair_reference2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type, second_param_type)
|
||||
{
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
// second param construct:
|
||||
@@ -252,7 +252,7 @@ struct compressed_pair_array1_tester
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
void compressed_pair_array1_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type, second_param_type)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
@@ -282,7 +282,7 @@ struct compressed_pair_array2_tester
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
void compressed_pair_array2_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type, second_param_type)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
@@ -312,7 +312,7 @@ struct compressed_pair_array_tester
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type p3, second_param_type p4)
|
||||
void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_param_type p2, first_param_type, second_param_type)
|
||||
{
|
||||
// default construct:
|
||||
boost::compressed_pair<T1,T2> cp1;
|
||||
@@ -329,7 +329,7 @@ void compressed_pair_array_tester<T1, T2>::test(first_param_type p1, second_para
|
||||
BOOST_TEST(sizeof(T2) == sizeof(cp1.second()));
|
||||
}
|
||||
|
||||
int test_main(int argc, char *argv[ ])
|
||||
int test_main(int, char **)
|
||||
{
|
||||
// declare some variables to pass to the tester:
|
||||
non_empty1 ne1(2);
|
||||
|
@@ -308,7 +308,7 @@ implementation, the <tt>difference_type</tt> for any variable-length signed
|
||||
integer type <tt>T</tt> is <tt>T</tt> itself.
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->19 Aug 2001<!--webbot bot="Timestamp" endspan i-checksum="14767" --></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"
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include <climits>
|
||||
#include <iterator>
|
||||
#include <stdlib.h>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
|
55
include/boost/ref.hpp
Normal file
55
include/boost/ref.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef BOOST_REF_HPP_INCLUDED
|
||||
#define BOOST_REF_HPP_INCLUDED
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//
|
||||
// ref.hpp - ref/cref, useful helper functions
|
||||
//
|
||||
// Version 1.00.0003 (2001-08-22)
|
||||
//
|
||||
// Copyright (C) 1999, 2000 Jaakko J<>rvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// 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/libs/bind/ref.html for documentation.
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<class T> class reference_wrapper
|
||||
{
|
||||
public:
|
||||
|
||||
explicit reference_wrapper(T & t): t_(t) {}
|
||||
|
||||
operator T & () const { return t_; }
|
||||
|
||||
T & get() const { return t_; }
|
||||
|
||||
private:
|
||||
|
||||
T & t_;
|
||||
|
||||
reference_wrapper & operator= (reference_wrapper const &);
|
||||
};
|
||||
|
||||
template<class T> inline reference_wrapper<T> ref(T & t)
|
||||
{
|
||||
return reference_wrapper<T>(t);
|
||||
}
|
||||
|
||||
template<class T> inline reference_wrapper<T const> cref(T const & t)
|
||||
{
|
||||
return reference_wrapper<T const>(t);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_REF_HPP_INCLUDED
|
@@ -10,23 +10,15 @@
|
||||
|
||||
// Classes appear in alphabetical order
|
||||
|
||||
// Revision History
|
||||
// 21 May 01 checked_delete() and checked_array_delete() added (Beman Dawes,
|
||||
// suggested by Dave Abrahams, generalizing idea from Vladimir Prus)
|
||||
// 21 May 01 made next() and prior() inline (Beman Dawes)
|
||||
// 26 Jan 00 protected noncopyable destructor added (Miki Jovanovic)
|
||||
// 10 Dec 99 next() and prior() templates added (Dave Abrahams)
|
||||
// 30 Aug 99 moved cast templates to cast.hpp (Beman Dawes)
|
||||
// 3 Aug 99 cast templates added
|
||||
// 20 Jul 99 name changed to utility.hpp
|
||||
// 9 Jun 99 protected noncopyable default ctor
|
||||
// 2 Jun 99 Initial Version. Class noncopyable only contents (Dave Abrahams)
|
||||
|
||||
#ifndef BOOST_UTILITY_HPP
|
||||
#define BOOST_UTILITY_HPP
|
||||
|
||||
#include <boost/config.hpp> // broken compiler workarounds
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/config.hpp> // broken compiler workarounds
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
// certain headers are part of the <utility.hpp> interface
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
#include <utility> // for std::pair
|
||||
|
||||
@@ -87,31 +79,6 @@ namespace boost
|
||||
const noncopyable& operator=( const noncopyable& );
|
||||
}; // noncopyable
|
||||
|
||||
// class tied -------------------------------------------------------//
|
||||
|
||||
// A helper for conveniently assigning the two values from a pair
|
||||
// into separate variables. The idea for this comes from Jaakko J<>rvi's
|
||||
// Binder/Lambda Library.
|
||||
|
||||
// Constributed by Jeremy Siek
|
||||
|
||||
template <class A, class B>
|
||||
class tied {
|
||||
public:
|
||||
inline tied(A& a, B& b) : _a(a), _b(b) { }
|
||||
template <class U, class V>
|
||||
inline tied& operator=(const std::pair<U,V>& p) {
|
||||
_a = p.first;
|
||||
_b = p.second;
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
A& _a;
|
||||
B& _b;
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
inline tied<A,B> tie(A& a, B& b) { return tied<A,B>(a, b); }
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
59
include/boost/utility/base_from_member.hpp
Normal file
59
include/boost/utility/base_from_member.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// boost utility/base_from_member.hpp header file --------------------------//
|
||||
|
||||
// (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.
|
||||
|
||||
#ifndef BOOST_UTILITY_BASE_FROM_MEMBER_HPP
|
||||
#define BOOST_UTILITY_BASE_FROM_MEMBER_HPP
|
||||
|
||||
#include <boost/utility_fwd.hpp> // required for parameter defaults
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// Base-from-member class template -----------------------------------------//
|
||||
|
||||
// Helper to initialize a base object so a derived class can use this
|
||||
// object in the initialization of another base class. Used by
|
||||
// Dietmar Kuehl from ideas by Ron Klatcho to solve the problem of a
|
||||
// base class needing to be initialized by a member.
|
||||
|
||||
// Contributed by Daryle Walker
|
||||
|
||||
template < typename MemberType, int UniqueID >
|
||||
class base_from_member
|
||||
{
|
||||
protected:
|
||||
MemberType member;
|
||||
|
||||
explicit base_from_member()
|
||||
: member()
|
||||
{}
|
||||
|
||||
template< typename T1 >
|
||||
explicit base_from_member( T1 x1 )
|
||||
: member( x1 )
|
||||
{}
|
||||
|
||||
template< typename T1, typename T2 >
|
||||
base_from_member( T1 x1, T2 x2 )
|
||||
: member( x1, x2 )
|
||||
{}
|
||||
|
||||
template< typename T1, typename T2, typename T3 >
|
||||
base_from_member( T1 x1, T2 x2, T3 x3 )
|
||||
: member( x1, x2, x3 )
|
||||
{}
|
||||
|
||||
}; // boost::base_from_member
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_UTILITY_BASE_FROM_MEMBER_HPP
|
38
include/boost/utility_fwd.hpp
Normal file
38
include/boost/utility_fwd.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Boost utility_fwd.hpp header file ---------------------------------------//
|
||||
|
||||
// (C) Copyright boost.org 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.
|
||||
|
||||
#ifndef BOOST_UTILITY_FWD_HPP
|
||||
#define BOOST_UTILITY_FWD_HPP
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
|
||||
// From <boost/utility/base_from_member.hpp> -------------------------------//
|
||||
|
||||
template < typename MemberType, int UniqueID = 0 >
|
||||
class base_from_member;
|
||||
|
||||
|
||||
// From <boost/utility.hpp> ------------------------------------------------//
|
||||
|
||||
class noncopyable;
|
||||
|
||||
template < class A, class B >
|
||||
class tied;
|
||||
|
||||
// Also has a few function templates
|
||||
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_UTILITY_FWD_HPP
|
@@ -203,10 +203,10 @@ explicit indirect_iterator_generator::type(const BaseIterator& it)
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
template <class BaseIterator,
|
||||
class Value, class Pointer, class Reference,
|
||||
class ConstPointer, class ConstReference>
|
||||
class indirect_iterator_pair_generator
|
||||
template <class BaseIterator,
|
||||
class Value, class Reference, class ConstReference,
|
||||
class Category, class Pointer, class ConstPointer>
|
||||
struct indirect_iterator_pair_generator;
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href=
|
||||
@@ -292,13 +292,6 @@ b,c,d,e,f,g,h,
|
||||
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>
|
||||
|
||||
@@ -307,6 +300,19 @@ b,c,d,e,f,g,h,
|
||||
<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>
|
||||
|
||||
<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>ConstPointer</tt>
|
||||
|
||||
@@ -314,11 +320,6 @@ b,c,d,e,f,g,h,
|
||||
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>
|
||||
@@ -422,7 +423,7 @@ a,b,c,d,e,f,g,
|
||||
<hr>
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->18 Sep 2001<!--webbot bot="Timestamp" endspan i-checksum="14941" -->
|
||||
|
||||
|
||||
<p>© Copyright Jeremy Siek and David Abrahams 2001. Permission to
|
||||
|
@@ -93,7 +93,7 @@
|
||||
<a href="function_output_iterator.htm">Function Output Iterator Adaptor</a>
|
||||
</ul>
|
||||
|
||||
<p><b><a href="file:///c:/boost/site/people/dave_abrahams.htm">Dave
|
||||
<p><b><a href="../../people/dave_abrahams.htm">Dave
|
||||
Abrahams</a></b> started the library, applying <a href=
|
||||
"../../more/generic_programming.html#policy">policy class</a> technique and
|
||||
handling const/non-const iterator interactions. He also contributed the
|
||||
@@ -102,7 +102,7 @@
|
||||
<tt><a href="counting_iterator.htm">counting_iterator_generator</a></tt> to
|
||||
cover all incrementable types. He edited most of the documentation,
|
||||
sometimes heavily.<br>
|
||||
<b><a href="file:///c:/boost/site/people/jeremy_siek.htm">Jeremy
|
||||
<b><a href="../../people/jeremy_siek.htm">Jeremy
|
||||
Siek</a></b> contributed the <a href="transform_iterator.htm">transform
|
||||
iterator</a> adaptor, the integer-only version of <tt><a href=
|
||||
"counting_iterator.htm">counting_iterator_generator</a></tt>,
|
||||
@@ -423,27 +423,27 @@ struct <a name="default_iterator_policies">default_iterator_policies</a>
|
||||
{ return *x; }
|
||||
|
||||
template <class BaseType>
|
||||
static void increment(BaseType& x)
|
||||
void increment(BaseType& x)
|
||||
{ ++x; }
|
||||
|
||||
template <class BaseType1, class BaseType2>
|
||||
bool equal(BaseType1& x, BaseType2& y) const
|
||||
bool equal(const BaseType1& x, const BaseType2& y) const
|
||||
{ return x == y; }
|
||||
|
||||
template <class BaseType>
|
||||
static void decrement(BaseType& x)
|
||||
void decrement(BaseType& x)
|
||||
{ --x; }
|
||||
|
||||
template <class BaseType, class DifferenceType>
|
||||
static void advance(BaseType& x, DifferenceType n)
|
||||
void advance(BaseType& x, DifferenceType n)
|
||||
{ x += n; }
|
||||
|
||||
template <class Difference, class BaseType1, class BaseType2>
|
||||
Difference distance(type<Difference>, BaseType1& x, BaseType2& y) const
|
||||
Difference distance(type<Difference>, const BaseType1& x, const BaseType2& y) const
|
||||
{ return y - x; }
|
||||
|
||||
template <class BaseType1, class BaseType2>
|
||||
bool less(BaseType1& x, BaseType2& y) const
|
||||
bool less(const BaseType1& x, const BaseType2& y) const
|
||||
{ return x < y; }
|
||||
};
|
||||
</pre>
|
||||
@@ -611,10 +611,10 @@ int main(int, char*[])
|
||||
{
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
const int N = sizeof(x)/sizeof(int);
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
std::copy(boost::make_transform_iterator(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||
boost::make_transform_iterator(x + N, std::bind1st(std::multiplies<int>(), 2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -767,10 +767,10 @@ struct iterator_adaptor
|
||||
iterator_adaptor(
|
||||
const iterator_adaptor<B,Policies,V,R,P,Category,Distance>&);
|
||||
|
||||
reference operator*() const;
|
||||
reference operator*() const; <a href="#6">[6]</a>
|
||||
<i>operator_arrow_result_type</i> operator->() const; <a href=
|
||||
"#3">[3]</a>
|
||||
<i>value_type</i> operator[](difference_type n) const; <a href="#3">[4]</a>
|
||||
<i>value_type</i> operator[](difference_type n) const; <a href="#3">[4]</a>, <a href="#6">[6]</a>
|
||||
|
||||
iterator_adaptor& operator++();
|
||||
iterator_adaptor& operator++(int);
|
||||
@@ -857,10 +857,38 @@ bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&,
|
||||
Forward Iterator</a>, so you will need to use a less restrictive
|
||||
iterator category such as <tt>std::input_iterator_tag</tt>.
|
||||
|
||||
<p><a name="6">[6]</a>
|
||||
There is a common misconception that an iterator should have two
|
||||
versions of <tt>operator*</tt> and of <tt>operator[]</tt>, one
|
||||
version that is a <tt>const</tt> member function and one version
|
||||
that is non-<tt>const</tt>. Perhaps the source of this
|
||||
misconception is that containers typically have const and
|
||||
non-const versions of many of their member functions. Iterators,
|
||||
however, are different. A particular iterator type can be either
|
||||
<i>mutable</i> or <i>constant</i> (but not both). One can assign
|
||||
to and change the object pointed to by a mutable iterator whereas a
|
||||
constant iterator returns constant objects when dereferenced. Whether
|
||||
the iterator object itself is <tt>const</tt> has nothing to do with
|
||||
whether the iterator is mutable or constant. This is analogous to
|
||||
the way built-in pointer types behave. For example, one can
|
||||
modify objects pointed to by a <tt>const</tt> pointer
|
||||
<pre>
|
||||
int* const x = new int;
|
||||
int i = 3;
|
||||
*x = i;
|
||||
</pre>
|
||||
but one cannot modify objects pointed to by a pointer
|
||||
to <tt>const</tt>
|
||||
<pre>
|
||||
int const* x = new int;
|
||||
int i = 3;
|
||||
*x = i;
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->12 Jul 2001<!--webbot bot="Timestamp" endspan i-checksum="14985" -->
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->18 Sep 2001<!--webbot bot="Timestamp" endspan i-checksum="14941" -->
|
||||
|
||||
|
||||
<p>© Copyright Dave Abrahams and Jeremy Siek 2001. Permission to copy,
|
||||
@@ -871,7 +899,7 @@ bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&,
|
||||
|
||||
</body>
|
||||
|
||||
<!-- LocalWords: HTML html charset alt gif abrahams htm const
|
||||
<!-- LocalWords: HTML html charset alt gif abrahams htm const iterator
|
||||
incrementable david abrahams
|
||||
-->
|
||||
|
||||
@@ -887,5 +915,7 @@ bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&,
|
||||
<!-- LocalWords: iostream hpp sizeof InputIterator constness ConstIterator
|
||||
David Abrahams
|
||||
-->
|
||||
<!-- LocalWords: Iterators dereferenced
|
||||
-->
|
||||
</html>
|
||||
|
||||
|
@@ -371,7 +371,7 @@ Betty
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" --></p>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->19 Aug 2001<!--webbot bot="Timestamp" endspan i-checksum="14767" --></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"
|
||||
|
@@ -312,7 +312,7 @@ simply use <tt>reverse_iterator_generator</tt> twice!<br><br>
|
||||
|
||||
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->08 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14892" -->
|
||||
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->19 Aug 2001<!--webbot bot="Timestamp" endspan i-checksum="14767" -->
|
||||
|
||||
|
||||
<p>© Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell
|
||||
|
10
tie.html
10
tie.html
@@ -24,8 +24,12 @@
|
||||
</H1>
|
||||
|
||||
<h3>
|
||||
[tie has been deprecated. Its functionality is supplied by the Boost
|
||||
Tuples Library.]</h3>
|
||||
[This version of tie has been removed from the utility.hpp
|
||||
header. There is a new, more general version of <a
|
||||
href="../tuple/doc/tuple_users_guide.html#tiers">tie</a> in the Boost
|
||||
Tuples Library. The more general version handles an (almost) arbitrary
|
||||
number of arguments, instead of just two. The version in utility.hpp
|
||||
had to be removed to avoid name clashes.]</h3>
|
||||
<PRE>
|
||||
template <class A, class B>
|
||||
tied<A,B> tie(A& a, B& b);
|
||||
@@ -126,7 +130,7 @@ The output is:
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=file:///c:/boost/site/people/jeremy_siek.htm>Jeremy Siek</A>,
|
||||
<a HREF="../../people/jeremy_siek.htm">Jeremy Siek</a>,
|
||||
Univ.of Notre Dame (<A
|
||||
HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)<br>
|
||||
<A HREF=http://www.lsc.nd.edu/~llee1>Lie-Quan Lee</A>, Univ.of Notre Dame (<A HREF="mailto:llee1@lsc.nd.edu">llee1@lsc.nd.edu</A>)<br>
|
||||
|
@@ -19,14 +19,16 @@
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/utility.hpp>
|
||||
// Note: tie() use to live in boost/utility.hpp, but
|
||||
// not it is part of the more general Boost Tuple Library.
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
int
|
||||
main(int, char*[])
|
||||
{
|
||||
{
|
||||
typedef std::set<int> SetT;
|
||||
SetT::iterator i, end;
|
||||
SetT::iterator i;
|
||||
bool inserted;
|
||||
|
||||
int vals[5] = { 5, 2, 4, 9, 1 };
|
||||
|
@@ -211,7 +211,7 @@ iterator always returns by-value.
|
||||
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->29 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14896" --></p>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->19 Aug 2001<!--webbot bot="Timestamp" endspan i-checksum="14767" --></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"
|
||||
|
@@ -16,6 +16,8 @@
|
||||
<h2>Contents</h2>
|
||||
|
||||
<ul>
|
||||
<li>Class templates supporting the <a href="base_from_member.html">base-from-member
|
||||
idiom</a></li>
|
||||
<li>Function templates <a href="#checked_delete">checked_delete() and
|
||||
checked_array_delete()</a></li>
|
||||
<li>Function templates <a href="#functions next">next() and prior()</a></li>
|
||||
@@ -131,11 +133,13 @@ emphasize that it is to be used only as a base class. Dave Abrahams notes
|
||||
concern about the effect on compiler optimization of adding (even trivial inline)
|
||||
destructor declarations. He says "Probably this concern is misplaced, because
|
||||
noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."</p>
|
||||
<h2>Class templates for the Base-from-Member Idiom</h2>
|
||||
<p>See <a href="base_from_member.html">separate documentation</a>.</p>
|
||||
<h2>Function template tie()</h2>
|
||||
<p>See <a href="tie.html">separate documentation</a>.</p>
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan
|
||||
-->22 May, 2001<!--webbot bot="Timestamp" endspan i-checksum="13960"
|
||||
-->10 September, 2001<!--webbot bot="Timestamp" endspan i-checksum="39328"
|
||||
-->
|
||||
</p>
|
||||
<p><EFBFBD> Copyright boost.org 1999. Permission to copy, use, modify, sell and
|
||||
|
Reference in New Issue
Block a user