mirror of
https://github.com/boostorg/utility.git
synced 2025-10-08 06:50:53 +02:00
Compare commits
33 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 | ||
|
31d0908b74 | ||
|
32c77599f4 | ||
|
812ebf3562 | ||
|
37f476013d | ||
|
9f3104166f | ||
|
64cc0daf34 | ||
|
d5d64df124 | ||
|
0edcfcd5c1 | ||
|
50ba2d419a | ||
|
ff3a77ca5a | ||
|
4eaed6c23d | ||
|
4d0dd46471 |
@@ -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=http://www.boost.org/people/jeremy_siek.htm>Jeremy Siek</A>, Univ.of Notre Dame (<A HREF="mailto:jsiek@lsc.nd.edu">jsiek@lsc.nd.edu</A>)
|
||||
<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,23 +203,23 @@ int main(int argc, char *argv[ ])
|
||||
int i = 2;
|
||||
c2(i);
|
||||
int* pi = &i;
|
||||
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||
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);
|
||||
call_traits_checker<int&> c4;
|
||||
c4(i);
|
||||
call_traits_checker<const int&> c5;
|
||||
c5(i);
|
||||
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
int a[2] = {1,2};
|
||||
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__MWERKS__)
|
||||
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);
|
||||
@@ -238,7 +248,7 @@ int main(int argc, char *argv[ ])
|
||||
type_test(int&, boost::call_traits<int&>::reference)
|
||||
type_test(const int&, boost::call_traits<int&>::const_reference)
|
||||
type_test(int&, boost::call_traits<int&>::param_type)
|
||||
#if !(defined(__GNUC__) && (__GNUC__ < 3))
|
||||
#if !(defined(__GNUC__) && (__GNUC__ < 4))
|
||||
type_test(int&, boost::call_traits<cr_type>::value_type)
|
||||
type_test(int&, boost::call_traits<cr_type>::reference)
|
||||
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
||||
@@ -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>
|
||||
|
@@ -9,6 +9,9 @@
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 25 Jun 01 output_iterator_helper changes: removed default template
|
||||
// parameters, added support for self-proxying, additional
|
||||
// documentation and tests (Aleksey Gurtovoy)
|
||||
// 29 May 01 Added operator classes for << and >>. Added input and output
|
||||
// iterator helper classes. Added classes to connect equality and
|
||||
// relational operators. Added classes for groups of related
|
||||
@@ -702,15 +705,15 @@ struct input_iterator_helper
|
||||
, boost::iterator<std::input_iterator_tag, V, D, P, R
|
||||
> > > > {};
|
||||
|
||||
template <class T,
|
||||
class V = void,
|
||||
class D = void,
|
||||
class P = void,
|
||||
class R = void>
|
||||
template<class Derived>
|
||||
struct output_iterator_helper
|
||||
: incrementable<T
|
||||
, boost::iterator<std::output_iterator_tag, V, D, P, R
|
||||
> > {};
|
||||
: boost::incrementable<Derived
|
||||
, boost::iterator<std::output_iterator_tag, void, void, void, void
|
||||
> >
|
||||
{
|
||||
Derived& operator*() { return static_cast<Derived&>(*this); }
|
||||
Derived& operator++() { return static_cast<Derived&>(*this); }
|
||||
};
|
||||
|
||||
template <class T,
|
||||
class V,
|
||||
|
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="http://www.boost.org/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="http://www.boost.org/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 -->19 Mar 2001<!--webbot bot="Timestamp" endspan i-checksum="14895" -->
|
||||
<!--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>
|
||||
|
||||
|
@@ -26,6 +26,10 @@
|
||||
#include <string> // for std::string
|
||||
#include <strstream> // for std::ostrstream
|
||||
|
||||
# ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::strcmp; }
|
||||
# endif
|
||||
|
||||
|
||||
// Iterator test class
|
||||
template <class T, class R, class P>
|
||||
@@ -106,10 +110,10 @@ private:
|
||||
|
||||
|
||||
// Class-static data definitions
|
||||
typename test_opr_base::fruit_array_type
|
||||
test_opr_base::fruit_array_type
|
||||
test_opr_base::fruit = { "apple", "orange", "pear", "peach", "grape", "plum" };
|
||||
|
||||
typename test_opr_base::scratch_array_type
|
||||
test_opr_base::scratch_array_type
|
||||
test_opr_base::scratch = "";
|
||||
|
||||
template <typename T, typename R, typename P>
|
||||
|
@@ -7,6 +7,7 @@
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 1 Apr 2001 Fixes for ICL; use BOOST_STATIC_CONSTANT
|
||||
// 11 Feb 2001 Fixes for Borland (David Abrahams)
|
||||
// 23 Jan 2001 Added test for wchar_t (David Abrahams)
|
||||
// 23 Jan 2001 Now statically selecting a test for signed numbers to avoid
|
||||
@@ -30,13 +31,6 @@
|
||||
# include <limits>
|
||||
#endif
|
||||
|
||||
// A macro for declaring class compile-time constants.
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
# define DECLARE_CLASS_CONST(type, init) static const type init
|
||||
#else
|
||||
# define DECLARE_CLASS_CONST(type, init) enum { init }
|
||||
#endif
|
||||
|
||||
// =================================================================================
|
||||
// template class complement_traits<Number> --
|
||||
//
|
||||
@@ -53,8 +47,8 @@ template <unsigned size> struct complement; // forward
|
||||
template <class Number, unsigned size>
|
||||
struct complement_traits_aux
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = complement<size>::template traits<Number>::max);
|
||||
DECLARE_CLASS_CONST(Number, min = complement<size>::template traits<Number>::min);
|
||||
BOOST_STATIC_CONSTANT(Number, max = complement<size>::template traits<Number>::max);
|
||||
BOOST_STATIC_CONSTANT(Number, min = complement<size>::template traits<Number>::min);
|
||||
};
|
||||
|
||||
template <unsigned size>
|
||||
@@ -67,11 +61,11 @@ struct complement
|
||||
// indirection through complement_traits_aux neccessary to keep MSVC happy
|
||||
typedef complement_traits_aux<Number, size - 1> prev;
|
||||
public:
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
BOOST_STATIC_CONSTANT(Number, max =
|
||||
Number(Number(prev::max) << CHAR_BIT)
|
||||
+ Number(UCHAR_MAX));
|
||||
|
||||
DECLARE_CLASS_CONST(Number, min = Number(Number(prev::min) << CHAR_BIT));
|
||||
BOOST_STATIC_CONSTANT(Number, min = Number(Number(prev::min) << CHAR_BIT));
|
||||
};
|
||||
};
|
||||
|
||||
@@ -85,8 +79,8 @@ template <> struct complement_base<false>
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = 0);
|
||||
DECLARE_CLASS_CONST(Number, max = UCHAR_MAX);
|
||||
BOOST_STATIC_CONSTANT(Number, min = 0);
|
||||
BOOST_STATIC_CONSTANT(Number, max = UCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -95,8 +89,8 @@ template <> struct complement_base<true>
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = SCHAR_MIN);
|
||||
DECLARE_CLASS_CONST(Number, max = SCHAR_MAX);
|
||||
BOOST_STATIC_CONSTANT(Number, min = SCHAR_MIN);
|
||||
BOOST_STATIC_CONSTANT(Number, max = SCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -107,10 +101,10 @@ struct complement<1>
|
||||
template <class Number>
|
||||
struct traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(bool, is_signed = boost::detail::is_signed<Number>::value);
|
||||
DECLARE_CLASS_CONST(Number, min =
|
||||
BOOST_STATIC_CONSTANT(bool, is_signed = boost::detail::is_signed<Number>::value);
|
||||
BOOST_STATIC_CONSTANT(Number, min =
|
||||
complement_base<is_signed>::template values<Number>::min);
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
BOOST_STATIC_CONSTANT(Number, max =
|
||||
complement_base<is_signed>::template values<Number>::max);
|
||||
};
|
||||
};
|
||||
@@ -121,8 +115,8 @@ struct complement<1>
|
||||
template <class Number>
|
||||
struct complement_traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
|
||||
DECLARE_CLASS_CONST(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
|
||||
BOOST_STATIC_CONSTANT(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
|
||||
BOOST_STATIC_CONSTANT(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
|
||||
};
|
||||
|
||||
// =================================================================================
|
||||
@@ -151,9 +145,9 @@ template <> struct stream_as<signed char> {
|
||||
typedef unsigned char t1; typedef unsigned t2;
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
#if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
|
||||
|
||||
// On this platform, __int64 and __uint64 get streamed as strings
|
||||
// With this library implementation, __int64 and __uint64 get streamed as strings
|
||||
template <> struct stream_as<boost::uintmax_t> {
|
||||
typedef std::string t1;
|
||||
typedef std::string t2;
|
||||
@@ -174,7 +168,7 @@ template <class T> struct promote
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
#if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
|
||||
|
||||
// On this platform, stream them as long/unsigned long if they fit.
|
||||
// Otherwise, write a string.
|
||||
|
@@ -50,6 +50,7 @@ provided by the class.</p>
|
||||
<ul>
|
||||
<li><a href="#dereference">Dereference operators</a></li>
|
||||
<li><a href="#iterator">Iterator Helpers</a></li>
|
||||
<li><a href="#iterator_helpers_notes">Iterator Helper Notes</a></li>
|
||||
<li><a href="#i_demo">Iterator Demonstration and Test
|
||||
Program</a></li>
|
||||
</ul></li>
|
||||
@@ -821,7 +822,7 @@ from previous versions of the header, cannot be used for
|
||||
<p>The <cite><a href="operators_test.cpp">operators_test.cpp</a></cite>
|
||||
program demonstrates the use of the arithmetic operator templates, and
|
||||
can also be used to verify correct operation. Check the <a
|
||||
href="../compiler_status.htm">compiler status report</a> for the test results
|
||||
href="../../status/compiler_status.html">compiler status report</a> for the test results
|
||||
with selected platforms.</p>
|
||||
|
||||
<h2><a name="deref">Dereference</a> Operators and Iterator Helpers</h2>
|
||||
@@ -889,7 +890,7 @@ href="#chaining">base class chaining</a>.</p>
|
||||
|
||||
<h3><a name="iterator">Iterator</a> Helpers</h3>
|
||||
|
||||
<p>There are three separate iterator helper classes, each for a
|
||||
<p>There are five separate iterator helper classes, each for a
|
||||
different category of iterator. Here is a summary of the core set of
|
||||
operators that the custom iterator must define, and the extra operators
|
||||
that are created by the helper classes. These classes cannot be used for <a
|
||||
@@ -931,11 +932,13 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
|
||||
</ul></td>
|
||||
</tr>
|
||||
<tr valign="baseline">
|
||||
<td><code><a name="output_iterator_helper">output_iterator_helper<T, V, D, P, R></a></code></td>
|
||||
<td><code><a name="output_iterator_helper">output_iterator_helper<T></a></code></td>
|
||||
<td>Supports the operations and has the requirements of
|
||||
<ul>
|
||||
<li><code><a href="#incrementable">incrementable<T></a></code></li>
|
||||
</ul></td>
|
||||
</ul>
|
||||
See also [<a href="#1">1</a>], [<a href="#2">2</a>].
|
||||
</td>
|
||||
</tr>
|
||||
<tr valign="baseline">
|
||||
<td><code><a name="forward_iterator_helper">forward_iterator_helper<T, V, D, P, R></a></code></td>
|
||||
@@ -975,6 +978,53 @@ C++ standard (<code>iterator_category</code>, <code>value_type</code>,
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3><a name="iterator_helpers_notes">Iterator Helper Notes</a></h3>
|
||||
|
||||
<p><a name="1">[1]</a> Unlike other iterator helpers templates,
|
||||
<code>output_iterator_helper</code> takes only one template parameter - the type of
|
||||
its target class. Although to some it might seem like an unnecessary
|
||||
restriction, the standard requires <code>difference_type</code> and
|
||||
<code>value_type</code> of any output iterator to be
|
||||
<code>void</code> (24.3.1 [lib.iterator.traits]), and
|
||||
<code>output_iterator_helper</code> template respects this
|
||||
requirement. Also, output iterators in the standard have void <tt>pointer</tt> and
|
||||
<tt>reference</tt> types, so the <tt>output_iterator_helper</tt> does the
|
||||
same.
|
||||
|
||||
<p><a name="2">[2]</a> As self-proxying is the easiest and most common way to
|
||||
implement output iterators (see, for example, insert [24.4.2] and stream
|
||||
iterators [24.5] in the standard library), <code>output_iterator_helper</code>
|
||||
supports the idiom by defining <code>operator*</code>
|
||||
and <code>operator++</code> member functions which just return a
|
||||
non-const reference to the iterator itself. Support for
|
||||
self-proxying allows us, in many cases, to reduce the task of writing an output
|
||||
iterator to writing just two member functions - an appropriate
|
||||
constructor and a copy-assignment operator. For example, here is a possible
|
||||
implementation of <code><a href="function_output_iterator.htm">boost::function_output_iterator</a></code>
|
||||
adaptor:</p>
|
||||
|
||||
<pre>
|
||||
template<class UnaryFunction>
|
||||
struct function_output_iterator
|
||||
: boost::output_iterator_helper< function_output_iterator<UnaryFunction> >
|
||||
{
|
||||
explicit function_output_iterator(UnaryFunction const& f = UnaryFunction())
|
||||
: func(f) {}
|
||||
|
||||
template<typename T>
|
||||
function_output_iterator& operator=(T const& value)
|
||||
{
|
||||
this->func(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
UnaryFunction func;
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>Note that support for self-proxying does not prevent you from using <code>output_iterator_helper</code> to ease any other, different kind of output iterator's implementation. If <code>output_iterator_helper</code>'s target type provides its own definition of <code>operator*</code> or/and <code>operator++</code>, then these operators will get used and the ones supplied by <code>output_iterator_helper</code> will never be instantiated.</p>
|
||||
|
||||
<h3><a name="i_demo">Iterator Demonstration</a> and Test Program</h3>
|
||||
|
||||
<p>The <cite><a href="iterators_test.cpp">iterators_test.cpp</a></cite>
|
||||
@@ -1010,7 +1060,7 @@ public:
|
||||
};</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Check the <a href="../compiler_status.htm">compiler status report</a> for
|
||||
<p>Check the <a href="../../status/compiler_status.html">compiler status report</a> for
|
||||
the test results with selected platforms.</p>
|
||||
|
||||
<hr>
|
||||
@@ -1092,7 +1142,7 @@ the library remain backward-compatible.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Revised: 20 May 2001</p>
|
||||
<p>Revised: 25 Jun 2001</p>
|
||||
|
||||
<p>Copyright © David Abrahams and Beman Dawes 1999-2001.
|
||||
Permission to copy, use, modify, sell and distribute this document is
|
||||
|
@@ -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
@@ -23,7 +23,13 @@
|
||||
<TT>tie</TT>
|
||||
</H1>
|
||||
|
||||
<P>
|
||||
<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);
|
||||
@@ -124,7 +130,7 @@ The output is:
|
||||
<TABLE>
|
||||
<TR valign=top>
|
||||
<TD nowrap>Copyright © 2000</TD><TD>
|
||||
<A HREF=http://www.boost.org/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 };
|
||||
|
@@ -1,75 +0,0 @@
|
||||
# -*- makefile -*-
|
||||
|
||||
DVIPS = dvips
|
||||
LATEX = pdflatex
|
||||
LATEXOUT = pdf
|
||||
RESULT = pdf
|
||||
|
||||
#LATEX = latex
|
||||
#LATEXOUT = dvi
|
||||
#RESULT = ps
|
||||
|
||||
.SUFFIXES: .tex .dvi .ps .pdf .c .lg .eps
|
||||
|
||||
.c.lg:
|
||||
lgrind -i -o $*.lg -a -lc++ $*.c
|
||||
|
||||
.eps.pdf:
|
||||
epstopdf $*.eps
|
||||
|
||||
.tex.pdf:
|
||||
@ if test ! -f $*.ind; then echo "" > $*.ind; fi
|
||||
@ $(LATEX) $*
|
||||
@ if ( grep 'Writing index file' $*.log > /dev/null ); \
|
||||
then makeindex $* ; $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Citation' $*.log > /dev/null ); \
|
||||
then bibtex $* ; $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
@ if ( grep 'LaTeX Warning: Label(s) may' $*.log > /dev/null ); \
|
||||
then $(LATEX) $* ; fi
|
||||
|
||||
.dvi.ps:
|
||||
$(DVIPS) -o $*.ps $*
|
||||
|
||||
.ps.pdf:
|
||||
distill -v -maxsubsetpct 99 -subsetfonts on -pairs $*.ps $*.pdf
|
||||
|
||||
|
||||
SRCCODE =
|
||||
|
||||
|
||||
#
|
||||
# Default rule
|
||||
#
|
||||
|
||||
default: iter-adaptor.$(RESULT)
|
||||
|
||||
|
||||
#
|
||||
# LaTeX stuff
|
||||
#
|
||||
TEX = iter-adaptor.tex
|
||||
|
||||
iter-adaptor.dvi: $(TEX) $(SRCCODELG)
|
||||
iter-adaptor.ps: iter-adaptor.dvi
|
||||
iter-adaptor.pdf: $(PDFPICT) $(TEX) $(SRCCODELG)
|
||||
|
||||
dist: iter-adaptor.ps iter-adaptor.pdf
|
||||
mkdir -p iter-adaptor
|
||||
cp $(TEX) $(SRCCODELG) $(EPS) $(PS) \
|
||||
iter-adaptor.bbl iter-adaptor.ps iter-adaptor.pdf \
|
||||
iter-adaptor
|
||||
tar cvf - ./iter-adaptor | gzip > iter-adaptor.tar.gz
|
||||
|
||||
#
|
||||
# Standard rules
|
||||
#
|
||||
|
||||
clean:
|
||||
/bin/rm -f *.dvi *.o *.ps *.pdf *.log *.blg *.bbl *.aux *~ *.out *.ind
|
||||
|
@@ -1,36 +0,0 @@
|
||||
|
||||
\usepackage{times}
|
||||
|
||||
\newif\ifpdf
|
||||
\ifx\pdfoutput\undefined
|
||||
\pdffalse
|
||||
\else
|
||||
\pdfoutput=1
|
||||
\pdftrue
|
||||
\fi
|
||||
|
||||
\ifpdf
|
||||
\usepackage[
|
||||
pdftex,
|
||||
colorlinks=true,
|
||||
linkcolor=blue,filecolor=blue,pagecolor=blue,urlcolor=blue
|
||||
]{hyperref}
|
||||
\fi
|
||||
|
||||
\ifpdf
|
||||
\newcommand{\concept}[1]{\hyperref[concept:#1]{\textsf{#1}}}
|
||||
\newcommand{\stlconcept}[1]{\href{http://www.sgi.com/Technology/STL/#1.html}{\textsf{#1}}}
|
||||
\newcommand{\link}[2]{\hyperref[#1]{#2}}
|
||||
\else
|
||||
\newcommand{\concept}[1]{\textsf{#1}}
|
||||
\newcommand{\stlconcept}[1]{\textsf{#1}}
|
||||
\newcommand{\href}[2]{#2}
|
||||
\newcommand{\link}[2]{#2}
|
||||
\fi
|
||||
|
||||
\newcommand{\code}[1]{{\small \texttt{#1}}}
|
||||
|
||||
\newcommand{\Note}[1]{\marginpar{\begin{flushleft}%
|
||||
{%%\tiny %%\footnotesize
|
||||
{\bf Note:} #1}%
|
||||
\end{flushleft}}}
|
@@ -1,423 +0,0 @@
|
||||
|
||||
% Introduction/Motivation, etc. (Dave & Jeremy)
|
||||
|
||||
% iterator policies (Dave)
|
||||
% default policies
|
||||
% type<> wrapper
|
||||
% \cite{alexandrescu01:_modern_cpp_design}
|
||||
|
||||
% iterator_comparisons base (B&N) (Jeremy) \cite{Barton94}
|
||||
% workaround for g++ compiler bug with friend functions?
|
||||
|
||||
% operator_array_proxy (Dave)
|
||||
|
||||
% default pointer/reference type selection (Dave)
|
||||
|
||||
% wrapping non-iterators (count_iterator) (Jeremy)
|
||||
|
||||
% named template parameters (Jeremy)
|
||||
|
||||
% operator[] return type (Dave)
|
||||
|
||||
% the static asserts (Dave)
|
||||
|
||||
% generators (Jeremy)
|
||||
% type generators
|
||||
% tempting to try to use inheritance to replace
|
||||
% templated typedef, but that doesn't work.
|
||||
% object generators
|
||||
|
||||
% const/non-const interoperability (Dave)
|
||||
|
||||
% implementing const/mutable iterators with the same class
|
||||
% common mistake is to make the return type of operator*()
|
||||
% depend on whether the iterator object is const/non-const.
|
||||
% See the transform iterator in \cite{TMPW00:Weiser}
|
||||
|
||||
% custom iterators \cite{TMPW00:Baus}
|
||||
% generating iterators
|
||||
% line iterator \cite{austern99:_gener_progr_stl}
|
||||
% constant iterator \cite{koenig97:_rumin_cpp}
|
||||
|
||||
% reverse iterator, front_insert_iterator, back_insert_iterator,
|
||||
% insert_iterator \cite{iso98:_cpp_final_draft_standard}
|
||||
|
||||
% view iterators
|
||||
% \cite{TMPW00:Weiser}
|
||||
|
||||
% future work, container adaptors
|
||||
|
||||
\documentclass{netobjectdays}
|
||||
|
||||
\input{defs}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\title{Generating Iterator Types}
|
||||
|
||||
\author{David Abrahams$^\dag$ and Jeremy Siek$^\ddag$ \\
|
||||
\\
|
||||
$^\dag$ Altra Broadband \\
|
||||
\texttt{abrahams@altrabroadband.com}\\
|
||||
\\
|
||||
$^\ddag$ Computer Science Department \\
|
||||
Indiana University \\
|
||||
Lindley Hall \\
|
||||
150 S. Woodlawn Ave. \\
|
||||
Bloomington, IN\ \ 47405-7104\\
|
||||
\texttt{jsiek@cs.indiana.edu}
|
||||
}
|
||||
|
||||
\maketitle
|
||||
|
||||
|
||||
\begin{abstract}
|
||||
The iterator abstraction is one of the most commonly used in
|
||||
programming and a considerable amount of time is spent building new
|
||||
iterator types. However, implementing an iterator type that satisfies
|
||||
the C++ Standard requirements for an iterator can be
|
||||
challenging. There are a number of common mistakes that people make,
|
||||
and there are necessary complexities in a C++ Standard conforming
|
||||
implementation that one would rather not have to think about. In this
|
||||
paper we present the iterator type generator in the Boost Iterator
|
||||
Adaptor Library. This generator simplifies the creation of iterators;
|
||||
it automates the error-prone and redundant parts of the implementation
|
||||
and greatly simplifies the creation of iterator types that are
|
||||
variations on other iterators (creating iterator adaptors). The
|
||||
design of the Iterator Adaptor Library is an example of policy-based
|
||||
design, and the implementation employs template meta-programming.
|
||||
\end{abstract}
|
||||
|
||||
|
||||
\section{Introduction}
|
||||
|
||||
%- defaults make it easy to adapt an iterator
|
||||
%- extensions from base operations to other operations make it
|
||||
% easier to create iterators
|
||||
|
||||
Iterators play an important role in modern C++ programing. The
|
||||
iterator is the central abstraction of the algorithms of the Standard
|
||||
Library and creating new iterator types and adapting old ones are
|
||||
common tasks for C++ programmers. There are plenty of examples of
|
||||
custom-made iterators in the literature: the
|
||||
\code{line\_iterator}~\cite{austern99:_gener_progr_stl},
|
||||
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
||||
\code{istream\_iterator} and
|
||||
\code{ostream\_iterator}~\cite{iso98:_cpp_final_draft_standard} to
|
||||
name a few. Also a growing number of generic iterator adaptors are
|
||||
available: \code{Checked\_iter}~\cite{stroustrup00:_cpp_prog_lang},
|
||||
iterators of the View Template Library~\cite{TMPW00:Weiser}, custom
|
||||
and smart iterators~\cite{becker98:_smart_iteraters,TMPW00:Baus},
|
||||
compound iterators~\cite{alexandrescu98:_compound_iters}, and several
|
||||
iterators in the MTL~\cite{siek99:_scitools}.
|
||||
|
||||
For an iterator to be usable with the Standard algorithms (and other
|
||||
generic algorithms in third-party libraries), it must fulfill the
|
||||
Standard requirements for an iterator type, which range from the few
|
||||
requirements of an \stlconcept{InputIterator} to the many requirements
|
||||
of a \stlconcept{RandomAccessIterator}. Implementing an iterator class
|
||||
that meets these requirements is a tedious and error-prone task
|
||||
despite the fact that most iterators are conceptually simple.
|
||||
|
||||
\subsection{Redundant Operators}
|
||||
|
||||
Perhaps the most obvious of reasons that implementing an iterator can
|
||||
be tediuos is that there are lots of redundant operators. That is,
|
||||
there are many operators that can be trivially defined in terms of
|
||||
other operators. For example, the \code{operator++(int)} is often best
|
||||
implemented in terms of \code{operator++()} as the example below
|
||||
shows.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
class iter {
|
||||
// ...
|
||||
iter& operator++() { /* ... */ return *this; }
|
||||
iter operator++(int) { iter tmp(*this); ++*this; return tmp; }
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
For a full \stlconcept{RandomAccessIterator}, there are a total of 17
|
||||
operators. 7 of the operators are fundamental while the other 10 are
|
||||
redundant.
|
||||
|
||||
% 7 core operations
|
||||
% 10 derived operations
|
||||
|
||||
% \code{operator->}
|
||||
% \code{operator[]}
|
||||
% \code{operator++(int)},
|
||||
% \code{operator--(int)},
|
||||
% \code{operator-=},
|
||||
% \code{operator+},
|
||||
% \code{operator!=},
|
||||
% \code{operator>},
|
||||
% \code{operator<=},
|
||||
% \code{operator>=}
|
||||
|
||||
|
||||
\subsection{Delagation of Operators for Iterator Adaptors}
|
||||
|
||||
It is often the case that an iterator adaptor changes the meaning of
|
||||
one or two operators while leaving the rest of the operators defined
|
||||
in the same way as the underlying iterator. This is typically
|
||||
implemented with delegating functions. The following example shows an
|
||||
excerpt from an \code{indirect\_iterator} adaptor, which takes an
|
||||
iterator over pointers and creates an iterator over the things pointed
|
||||
to. The \code{operator*} is changed to dereference twice but all the
|
||||
other operators stay the same. Writing all of the delegating functions
|
||||
for the \code{indirect\_iterator} would be a tedious task.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class Iterator> class indirect_iterator {
|
||||
public:
|
||||
// Adapt the meaning of dereference
|
||||
reference operator*() const {
|
||||
return **iter; // dereference twice
|
||||
}
|
||||
// Delegating the implementation to the underlying iterator.
|
||||
iter_adaptor& operator++() { ++iter; return *this; }
|
||||
iter_adaptor& operator--() { --iter; return *this; }
|
||||
// delegate for all the other operators...
|
||||
private:
|
||||
Iterator iter;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\subsection{Iterator Complexities}
|
||||
|
||||
In addition to the tedious aspects of iterator implementation, there
|
||||
are some complexities that trip up even the most experienced of
|
||||
programmers.
|
||||
|
||||
\subsubsection{Constant/Mutable Iterator Interactions}
|
||||
|
||||
One of the main situations in which iterators are used is inside
|
||||
containers. These iterators usually come in pairs: a constant iterator
|
||||
type and a mutable iterator type. It is desirable to allow the
|
||||
constant and mutable iterators to interoperate in terms of their
|
||||
binary operators. For example, suppose that you are implementing a
|
||||
container type \code{C}. Then you ought to define the following four
|
||||
version of \code{operator==}.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
bool operator==(const C::iterator& x, const C::iterator& y);
|
||||
bool operator==(const C::const_iterator& x, const C::iterator& y);
|
||||
bool operator==(const C::iterator& x, const C::const_iterator& y);
|
||||
bool operator==(const C::const_iterator& x, const C::const_iterator& y);
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
Implementers often forget to define the operators for const/mutable
|
||||
iterator interaction. In addition, iterator adaptors applied to these
|
||||
kinds of iterators should propagate the ability to interact. For
|
||||
example, a reverse iterator adaptor applied to \code{C::iterator} and
|
||||
\code{C::const\_iterator} should result in reverse iterator types that
|
||||
also have operators defined for the const/mutable interactions.
|
||||
|
||||
|
||||
\subsubsection{Constant/Mutable Iterator Implementation}
|
||||
|
||||
Another subtlety in the implementation of iterators is how the the
|
||||
distinction between constant and mutable iterators affects the
|
||||
implementation. It is obvious that a constant iterator should have a
|
||||
const \code{reference} type, while a mutable iterator should have a
|
||||
non-const \code{reference}, though in other regards the constant and
|
||||
mutable versions of an iterator are the same. It is therefore
|
||||
desirable to implement both versions of the iterator with a single
|
||||
class. It is possible to do this, however some care must be taken.
|
||||
One common mistake is that the programmer will confuse the difference
|
||||
between a const iterator object and a constant iterator. Such a
|
||||
misunderstanding can, for example, lead to an iterator class that has
|
||||
two versions of \code{operator*}, one that is a const member function
|
||||
and one that is not.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
// this is a mistake
|
||||
reference operator*();
|
||||
const_reference operator*() const;
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The right way to implement both a constant and mutable iterators using
|
||||
the same class is to make the iterator a class template and make the
|
||||
reference type a parameter. To create the constant iterator a const
|
||||
reference would be used as the template argument and to create the
|
||||
mutable iterator a non-const reference would be used as the template
|
||||
argument. There should be only one \code{operator*} that returns the
|
||||
\code{reference} type and the member function should be const since
|
||||
dereferencing an iterator does not change the state of the iterator
|
||||
object itself (unlike \code{operator++}).
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
// this is right
|
||||
reference operator*() const;
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
|
||||
\subsubsection{Input Iterators and \code{operator->}}
|
||||
|
||||
When creating an iterator adaptor that can accept an
|
||||
\stlconcept{InputIterator} as the adapted type some extra care must be
|
||||
taken in the implementation of \code{operator->}. \Note{Dave fills in
|
||||
the rest}
|
||||
|
||||
|
||||
|
||||
% Automatic implementation of redundant operators
|
||||
% Default delegation to adapted iterator
|
||||
|
||||
% complexities:
|
||||
% const-non const interaction
|
||||
% const/mutable iterator distinction
|
||||
% input iterator \code{operator->}
|
||||
|
||||
\section{The Boost \code{iterator\_adaptor}}
|
||||
|
||||
|
||||
|
||||
\subsection{Example}
|
||||
|
||||
It is often useful to automatically apply some function to the value
|
||||
returned by dereferencing an iterator. The transform iterator of the
|
||||
Iterator Adaptor Library makes it easy to create an iterator adaptor
|
||||
which does just that. Here we will show how easy it is to implement
|
||||
the transform iterator using the
|
||||
\code{iterator\_adaptor} template.
|
||||
|
||||
We want to be able to adapt a range of iterators and functions, so the
|
||||
policies class will have a template parameter for the function type
|
||||
and it will have a data member of that type. We know that the function
|
||||
takes one argument and that we'll need to be able to deduce the
|
||||
\code{result\_type} of the function so we can use it for the adapted
|
||||
iterator's \code{value\_type}. \stlconcept{AdaptableUnaryFunction} is
|
||||
the \textsf{concept}\cite{austern99:_gener_progr_stl} that fulfills
|
||||
those requirements.
|
||||
|
||||
To implement a transform iterator we will only change one of the base
|
||||
iterator's behaviors, so the \code{transform\_iterator\_policies}
|
||||
class can inherit the rest from \code{default\_iterator\_policies}. We
|
||||
will define the \code{dereference()} member function, which is used
|
||||
to implement \code{operator*()} of the adapted iterator. The
|
||||
implementation will dereference the base iterator and apply the
|
||||
function object. The \code{type<Reference>} parameter is used
|
||||
to convey the appropriate return type. The complete code for
|
||||
\code{transform\_iterator\_policies} is:
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction>
|
||||
struct transform_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
transform_iterator_policies() { }
|
||||
|
||||
transform_iterator_policies(const AdaptableUnaryFunction& f)
|
||||
: m_f(f) { }
|
||||
|
||||
template <class Reference, class BaseIterator>
|
||||
Reference dereference(type<Reference>, const BaseIterator& i) const
|
||||
{ return m_f(*i); }
|
||||
|
||||
AdaptableUnaryFunction m_f;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The next step is to use the \code{iterator\_adaptor} template to
|
||||
construct the transform iterator type. The nicest way to package the
|
||||
construction of the transform iterator is to create a \emph{type
|
||||
generator}, which is a class template whose sole purpose is to
|
||||
simplify the instantiation of some other complicated class
|
||||
template. It fulfills the same need as a templated typedef would if
|
||||
that were part of the {C++} language.
|
||||
|
||||
The first template parameter to the generator will be the type of the
|
||||
function object and the second will be the base iterator type. We use
|
||||
\code{iterator\_adaptor} to define the transform iterator type as a
|
||||
nested \code{typedef} inside the
|
||||
\code{transform\_iterator\_generator} class. Because the function may
|
||||
return by-value, we must limit the \code{iterator\_category} to
|
||||
\stlconcept{InputIterator}, and the iterator's \code{reference} type cannot be a
|
||||
true reference (the standard allows this for input iterators), so in
|
||||
this case we can use few of \code{iterator\_adaptor}'s default template
|
||||
arguments.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
struct transform_iterator_generator
|
||||
{
|
||||
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||
public:
|
||||
typedef iterator_adaptor<Iterator,
|
||||
transform_iterator_policies<AdaptableUnaryFunction>,
|
||||
value_type, value_type, value_type*, std::input_iterator_tag> type;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
As a finishing touch, we will create an
|
||||
\textsf{object generator} for the transform iterator, which
|
||||
is a function that makes it more convenient to create objects of some
|
||||
class template.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type
|
||||
make_transform_iterator(Iterator base,
|
||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
||||
{
|
||||
typedef typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type result_t;
|
||||
return result_t(base, f);
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
Here is an example that shows how to use a transform iterator to
|
||||
iterate through a range of numbers, multiplying each of them by 2
|
||||
and printing the result to standard output.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
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::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::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\noindent This output is:
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
2 4 6 8 10 12 14 16
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\bibliographystyle{abbrv}
|
||||
\bibliography{refs,tmpw00}
|
||||
|
||||
\end{document}
|
@@ -1,102 +0,0 @@
|
||||
% Paper Formatting according to requirements of Net.Objectdays 2000
|
||||
\LoadClass[10pt]{article}
|
||||
\pagestyle{empty}
|
||||
% ---------------------------------------------------------------------
|
||||
\textheight193mm
|
||||
\textwidth122mm
|
||||
\oddsidemargin44mm
|
||||
\hoffset-1in \voffset-1in
|
||||
\topmargin52mm
|
||||
\headsep0pt
|
||||
\headheight0pt
|
||||
% ---------------------------------------------------------------------
|
||||
\renewcommand\maketitle{\par
|
||||
\begingroup
|
||||
\renewcommand\thefootnote{\@fnsymbol\c@footnote}%
|
||||
\def\@makefnmark{\rlap{\@textsuperscript{\normalfont\@thefnmark}}}%
|
||||
\long\def\@makefntext##1{\parindent 1em\noindent
|
||||
\hb@xt@1.8em{%
|
||||
\hss\@textsuperscript{\normalfont\@thefnmark}}##1}%
|
||||
\if@twocolumn
|
||||
\ifnum \col@number=\@ne
|
||||
\@maketitle
|
||||
\else
|
||||
\twocolumn[\@maketitle]%
|
||||
\fi
|
||||
\else
|
||||
\newpage
|
||||
\global\@topnum\z@ % Prevents figures from going at top of page.
|
||||
\@maketitle
|
||||
\fi
|
||||
\thispagestyle{empty}\@thanks
|
||||
\endgroup
|
||||
\setcounter{footnote}{0}%
|
||||
\global\let\thanks\relax
|
||||
\global\let\maketitle\relax
|
||||
\global\let\@maketitle\relax
|
||||
\global\let\@thanks\@empty
|
||||
\global\let\@author\@empty
|
||||
\global\let\@date\@empty
|
||||
\global\let\@title\@empty
|
||||
\global\let\title\relax
|
||||
\global\let\author\relax
|
||||
\global\let\date\relax
|
||||
\global\let\and\relax
|
||||
}
|
||||
\date{}
|
||||
\def\@maketitle{%
|
||||
\newpage
|
||||
\null
|
||||
\vskip 2em%
|
||||
\begin{center}%
|
||||
\let \footnote \thanks
|
||||
{\Large \textbf{\@title} \par}%
|
||||
\vskip 1.5em%
|
||||
{\large
|
||||
\lineskip .5em%
|
||||
{\normalsize
|
||||
\begin{tabular}[t]{c}%
|
||||
\@author
|
||||
\end{tabular}\par}}%
|
||||
\vskip 1em%
|
||||
{\large \@date}%
|
||||
\end{center}%
|
||||
\par
|
||||
\vskip 1.5em}
|
||||
\renewcommand\section{\@startsection {section}{1}{\z@}%
|
||||
{-3.5ex \@plus -1ex \@minus -.2ex}%
|
||||
{2.3ex \@plus.2ex}%
|
||||
{\normalfont\large\bfseries}}
|
||||
\renewcommand\subsection{\@startsection{subsection}{2}{\z@}%
|
||||
{-3.25ex\@plus -1ex \@minus -.2ex}%
|
||||
{1.5ex \@plus .2ex}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%
|
||||
{-3.25ex\@plus -1ex \@minus -.2ex}%
|
||||
{1.5ex \@plus .2ex}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}%
|
||||
{3.25ex \@plus1ex \@minus.2ex}%
|
||||
{-1em}%
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand\subparagraph{\@startsection{subparagraph}{5}{\parindent}%
|
||||
{3.25ex \@plus1ex \@minus .2ex}%
|
||||
{-1em}%
|
||||
|
||||
{\normalfont\normalsize\bfseries}}
|
||||
\renewcommand{\figurename}{Fig}
|
||||
\renewcommand{\tablename}{Tab}
|
||||
\long\def\@makecaption#1#2{%
|
||||
\vskip\abovecaptionskip
|
||||
\sbox\@tempboxa{{\small\textbf{#1.} #2}}%
|
||||
\ifdim \wd\@tempboxa >\hsize
|
||||
{\small\textbf{#1.} #2}\par
|
||||
\else
|
||||
\global \@minipagefalse
|
||||
\hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
|
||||
\fi
|
||||
\vskip\belowcaptionskip}
|
||||
\renewenvironment{abstract}
|
||||
{\list{}{\leftmargin1cm\rightmargin\leftmargin}%
|
||||
\item\relax{\small \textbf{Abstract.}}}
|
||||
{\endlist}
|
@@ -1,94 +0,0 @@
|
||||
|
||||
@TechReport{stepa.lee-1994:the.s:TR,
|
||||
author = "A. A. Stepanov and M. Lee",
|
||||
title = "{The Standard Template Library}",
|
||||
institution = "ISO Programming Language C++ Project",
|
||||
year = "1994",
|
||||
number = "X3J16/94-0095, WG21/N0482",
|
||||
month = may,
|
||||
}
|
||||
|
||||
@Book{ austern99:_gener_progr_stl,
|
||||
author = "Matthew H. Austern",
|
||||
title = "Generic Programming and the {STL}",
|
||||
publisher = "Addison-Wesley",
|
||||
year = 1999,
|
||||
series = "Professional computing series"
|
||||
}
|
||||
|
||||
@Book{koenig97:_rumin_cpp,
|
||||
author = {Andrew Koenig and Barbara Moo},
|
||||
title = {Ruminations on {C++}},
|
||||
publisher = {Addison Wesley},
|
||||
year = 1997
|
||||
}
|
||||
|
||||
@Book{iso98:_cpp_final_draft_standard,
|
||||
author = "International Organization for Standardization
|
||||
(ISO)",
|
||||
title = "ISO/IEC Final Draft International Standard 14882:
|
||||
Programming Language C++",
|
||||
year = 1998,
|
||||
address = "1 rue de Varemb\'e, Case postale 56, CH-1211
|
||||
Gen\`eve 20, Switzerland"
|
||||
}
|
||||
|
||||
@Book{alexandrescu01:_modern_cpp_design,
|
||||
author = {Andrei Alexandrescu},
|
||||
title = {Modern {C++} Design},
|
||||
publisher = {Addison Wesley},
|
||||
year = 2001
|
||||
}
|
||||
|
||||
@BOOK { Barton94,
|
||||
AUTHOR = "John Barton and Lee Nackman",
|
||||
TITLE = "Scientific and Engineering {C++}",
|
||||
PUBLISHER = "Addison-Wesley",
|
||||
YEAR = 1994
|
||||
}
|
||||
|
||||
@Book{gamma95:_design_patterns,
|
||||
author = {Erich Gamma and Richard Helm and Ralph Johnson and John Vlissides},
|
||||
title = {Design Patterns: Elements of Reusable Object-Oriented Software},
|
||||
publisher = {Addison-Welsey},
|
||||
year = 1995,
|
||||
series = {Professional Computing}
|
||||
}
|
||||
|
||||
@Book{stroustrup00:_cpp_prog_lang,
|
||||
author = {Bjarne Stroustrup},
|
||||
title = {The {C++} Programming Language},
|
||||
publisher = {Addison-Wesley},
|
||||
year = 2000,
|
||||
edition = {Special}
|
||||
}
|
||||
|
||||
@Article{alexandrescu98:_compound_iters,
|
||||
author = {Andrei Alexandrescu},
|
||||
title = {Compound iterators of STL},
|
||||
journal = {{C/C++} Users Journal},
|
||||
year = 1998,
|
||||
volume = 16,
|
||||
number = 10,
|
||||
pages = {79-82},
|
||||
month = October
|
||||
}
|
||||
|
||||
@Article{becker98:_smart_iteraters,
|
||||
author = {Thomas Becker},
|
||||
title = {Smart Iterators and STL},
|
||||
journal = {{C/C++} Users Journal},
|
||||
year = 1998,
|
||||
volume = 16,
|
||||
number = 9,
|
||||
month = {September}
|
||||
}
|
||||
|
||||
@InBook{siek99:_scitools,
|
||||
author = {Jeremy G. Siek and Andrew Lumsdaine},
|
||||
title = {Modern Software Tools for Scientific Computing},
|
||||
chapter = {A Modern Framework for Portable High Performance
|
||||
Numerical Linear Algebra},
|
||||
publisher = {Birkhauser},
|
||||
year = 1999,
|
||||
}
|
@@ -1,249 +0,0 @@
|
||||
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Eisenecker,
|
||||
AUTHOR = "Ulrich W. Eisenecker and Frank Blinn and Krzysztof Czarnecki",
|
||||
TITLE = "A Solution to the Constructor-Problem of Mixin-Based Programming in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Mixin-Based Programming in C++ is a powerful programming style
|
||||
based on the parameterized inheritance idiom and the composition
|
||||
of C++ templates. Type expressions describing specific inheritance
|
||||
hierarchies can be composed either automatically using generative
|
||||
programming idioms in C++ or manually. Unfortunately, the mixin-based
|
||||
C++ programming techniques published to date do not adequately support
|
||||
optional and alternative mixin classes with constructors expecting
|
||||
varying numbers of arguments, which are common in practice. This
|
||||
is because the varying base class constructors do not provide a
|
||||
uniform interface on which the constructors of the derived classes
|
||||
could rely. This paper discusses several partial solutions to this
|
||||
problem that were proposed to date and presents a new, complete
|
||||
solution. The new solution uses generative programming techniques to
|
||||
automatically generate the appropriate constructors, and this way it
|
||||
avoids the overhead and clumsiness of instantiating composed mixin
|
||||
classes in the client code using the partial solutions. In fact,
|
||||
the new solution allows users to instantiate automatically composed
|
||||
mixin classes with the simplicity of instantiating concrete classes
|
||||
from traditional class hierarchies. Finally, the new solution does
|
||||
not suffer from the scalability problems of the partial solutions."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Berti,
|
||||
AUTHOR = "Guntram Berti",
|
||||
TITLE = "Generic Components for Grid Data Structures and Algorithms with {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Grids are fundamental data structures for representing
|
||||
geometric structures or their subdivisions. We propose a strategy
|
||||
for decoupling algorithms working on grids from the details of
|
||||
grid representations, using a generic programming approach in C++.
|
||||
Functionality of grid data structures is captured by a small set of
|
||||
primitives, divided into combinatorial and geometric ones. Special
|
||||
attention is paid to the generic implementation of grid functions, which
|
||||
correspond to the notion of mappings from grid elements (e. g. vertices)
|
||||
to entities of a given type. Experiments indicate that the overhead
|
||||
of the generic formulation is low and can be completely eliminated in
|
||||
some cases."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Veldhuizen,
|
||||
AUTHOR = "Todd L. Veldhuizen",
|
||||
TITLE = "Five compilation models for {C++} templates",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"This paper proposes an alternate structure for C++ compilers.
|
||||
Type analysis is removed from the compiler and replaced with a
|
||||
`type system library' which is treated as source code by the
|
||||
compiler. Type computations are embedded in the intermediate
|
||||
language of the compiler, and partial evaluation is used to drive
|
||||
type analysis and template instantiation. By making simple changes to
|
||||
the behavior of the partial evaluator, a wide range of compilation
|
||||
models is achieved, each with a distinct tradeoff of compile time, code
|
||||
size, and code speed. These models range from pure dynamic typing --
|
||||
ideal for scripting C++ -- to profile-directed template instantiation.
|
||||
This approach may solve several serious problems in compiling C++:
|
||||
it achieves separate compilation of templates, allows template
|
||||
code to be distributed in binary form by deferring template instantiation
|
||||
until run time, and reduces the code bloat associated with
|
||||
templates."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Baus,
|
||||
AUTHOR = "Christopher Baus and Thomas Becker",
|
||||
TITLE = "Custom Iterators for the {STL}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"We discuss several kinds of custom iterators for use with the STL
|
||||
that are substantially different from the iterators that come with
|
||||
the STL. We present class templates that implement these custom
|
||||
iterators in a generic manner."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Weiser,
|
||||
AUTHOR = "Martin Weiser and Gary Powell",
|
||||
TITLE = "The {View Template Library}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Views are container adaptors providing access to different
|
||||
on the fly generated representations of the data in the container they
|
||||
are applied to. The concept fits nicely into the framework defined by
|
||||
the STL. This paper explains design, usage, and implementation of the
|
||||
View Template Library, the currently most advanced implementation of
|
||||
the views concept."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Striegnitz,
|
||||
AUTHOR = "J{\"o}rg Striegnitz and Stephen A. Smith",
|
||||
TITLE = "An Expression Template aware Lambda Function",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Template libraries such as the STL contain several generic algorithms
|
||||
that expect functions as arguments and thereby cause frequent use of
|
||||
function objects. User-defined function objects are awkward because
|
||||
they must be declared as a class in namespace scope before they may
|
||||
be used. In this paper, we describe a lambda function for C++, which
|
||||
allows users to define function objects on the fly, without writing class
|
||||
declarations. We show that, by using expression templates, the lambda
|
||||
function can be implemented without hurting the runtime performance of a
|
||||
program. Expression templates can also help to overcome the performance
|
||||
penalties that may arise when using expressions over user-defined
|
||||
types. Thus, we based our approach on PETE which is a framework
|
||||
that simplifies the addition of expression template functionality to
|
||||
user-defined classes."
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@InProceedings{TMPW00:McNamara,
|
||||
AUTHOR = "Brian McNamara and Yannis Smaragdakis",
|
||||
TITLE = "Static Interfaces in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"We present an extensible framework for defining and
|
||||
using ``static interfaces'' in C++. Static interfaces are especially
|
||||
useful as constraints on template parameters. That is, in addition to the
|
||||
usual template $class T$, template definitions can specify that T ``isa''
|
||||
Foo, for some static interface named Foo. These ``isa-constraints'' can be
|
||||
based on either inheritance (named conformance: T publicly inherits Foo),
|
||||
members (structural conformance: T has these member functions with these
|
||||
signatures), or both. The constraint mechanism imposes no space or time
|
||||
overheads at runtime; virtual functions are conspicuously absent from
|
||||
our framework.
|
||||
|
||||
We demonstrate two key utilities of static interfaces. First,
|
||||
constraints enable better error messages with template code. By applying
|
||||
static interfaces as constraints, instantiating a template with the
|
||||
wrong type is an error that can be caught at the instantiation point,
|
||||
rather than later (typically in the bowels of the implementation).
|
||||
Authors of template classes and template functions can also dispatch
|
||||
``custom error messages'' to report named constraint violations by
|
||||
clients, making debugging easier. We show examples of the improvement of
|
||||
error messages when constraints are applied to STL code.
|
||||
|
||||
Second, constraints enable automatic compile-time dispatch of different
|
||||
implementations of class or function templates based on the named
|
||||
conformance properties of the template types. For example, $Set<T>$ can be
|
||||
written to automatically choose the most efficient implementation: use a
|
||||
hashtable implementation if ``T isa Hashable'', or else a binary search
|
||||
tree if ``T isa LessThanComparable'' , or else a linked-list if merely ``T
|
||||
isa EqualityComparable''. This dispatch can be completely hidden from
|
||||
clients of Set, who just use $Set<T>$ as usual."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Siek,
|
||||
AUTHOR = "Jeremy Siek and Andrew Lumsdaine",
|
||||
TITLE = "Concept Checking: Binding Parametric Polymorphism in {C++}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"Generic programming in C++ is characterized by the use of template
|
||||
parameters to represent abstract data types (or ``concepts'').
|
||||
However, the C++ language itself does not provide a mechanism for
|
||||
explicitly handling concepts. As a result, it can be difficult to
|
||||
insure that a concrete type meets the requirements of the concept it
|
||||
is supposed to represent. Error messages resulting from incorrect
|
||||
use of a concrete type can be particularly difficult to decipher.
|
||||
In this paper we present techniques to check parameters in generic
|
||||
C++ libraries. Our techniques use standard C++ and introduce no
|
||||
run-time overhead."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Kuehl,
|
||||
AUTHOR = "Dietmar K{\"u}hl",
|
||||
TITLE = "{STL} and {OO} Don't Easily Mix",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/",
|
||||
ABSTRACT =
|
||||
"The STL is a powerful tool for many kinds of processing. Unfortunately,
|
||||
using polymorphic objects with the STL seems not to work: Polymorphic
|
||||
objects stored in STL containers either get sliced (i.e. only the base
|
||||
part is copied or assigned but not the derived part) or, when storing
|
||||
pointers to them instead, are not destroyed. Applying algorithms to
|
||||
such containers often results in the wrong thing or complex predicate
|
||||
objects are needed. This article shows how to overcome at least some
|
||||
of these problems using some adaptors and also outlines a possible
|
||||
implementation of STL for better integration with polymorphic objects.
|
||||
The improved integration just acknowledges the distinction between the
|
||||
object and the entity used to maintain it."
|
||||
}
|
||||
|
||||
|
||||
@InProceedings{TMPW00:Eichelberger,
|
||||
AUTHOR = "H. Eichelberger and J. Wolff v. Gudenberg",
|
||||
TITLE = "{UML} Description of the {STL}",
|
||||
BOOKTITLE = "First Workshop on {C++} Template Programming,
|
||||
Erfurt, Germany",
|
||||
MONTH = "October 10",
|
||||
YEAR = "2000",
|
||||
URL = "http://oonumerics.org/tmpw00/eichelberger.pdf",
|
||||
ABSTRACT =
|
||||
"In this paper we show how the specification of the
|
||||
Standard Template Library STL and its implementation can be described
|
||||
by UML diagrams. We define appropriate stereotypes to
|
||||
describe STL concepts like containers, iterators, function
|
||||
objects and global algorithms. For the graphical description of the
|
||||
implementation of the STL we extend the UML metamodel."
|
||||
}
|
||||
|
@@ -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