Boost logo

Boost :

From: Daryle Walker (darylew_at_[hidden])
Date: 2001-03-25 09:42:46


The "more_io.zip" file in the vault contains helper classes for using Ron's
member idiom (within archived file "more_io.hpp"). Since these are of
general utility, maybe they should be in "utility.hpp" instead? Here's a
copy of the class templates:

//==========================================================================
namespace boost
{

// Forward declarations -----------------------------------------------//

template < typename MemberType, int UniqueID = 0 >
    class nullary_rons_member;
template < typename MemberType, typename InitializerType, int UniqueID = 0 >
    class unary_rons_member;
template < typename MemberType, typename InitializerType1,
           typename InitializerType2, int UniqueID = 0 >
    class binary_rons_member;

// Ron's member base class declarations -------------------------------//
// Used by Dietmar Kuehl <dietmar_kuehl_at_[hidden]> from
// Ron Klatchko <ron_at_[hidden]> to solve the problem of a
// base class needing to be initialized by a member.

template < typename MemberType, int UniqueID >
class nullary_rons_member
{
protected:
    nullary_rons_member();

    MemberType ron_;

}; // boost::nullary_rons_member

template < typename MemberType, typename InitializerType, int UniqueID >
class unary_rons_member
{
protected:
    explicit unary_rons_member( InitializerType x );

    MemberType ron_;

}; // boost::unary_rons_member

template < typename MemberType, typename InitializerType1,
           typename InitializerType2, int UniqueID >
class binary_rons_member
{
protected:
    binary_rons_member( InitializerType1 x, InitializerType2 y );

    MemberType ron_;

}; // boost::binary_rons_member

// Ron's member base class member definitions -------------------------//

template < typename MT, int UID >
inline
nullary_rons_member<MT, UID>::nullary_rons_member
(
)
    : ron_()
{
}

template < typename MT, typename IT, int UID >
inline
unary_rons_member<MT, IT, UID>::unary_rons_member
(
    IT x
)
    : ron_( x )
{
}

template < typename MT, typename IT1, typename IT2, int UID >
inline
binary_rons_member<MT, IT1, IT2, UID>::binary_rons_member
(
    IT1 x,
    IT2 y
)
    : ron_( x, y )
{
}

} // namespace boost
//==========================================================================

Here's the documentation clip:

//==========================================================================
<h2><a name="ron">Ron's Member Idiom</a></h2>

<h3><a name="ron_rat">Rationale</a></h3>

<p>When developing a class, sometimes a base class needs to be intialized
with a member of the current class. As a naive example:</p>

<blockquote><pre>
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(&amp;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>Custom base classes can be made to support this idiom, but this header
supplies three template classes to base the idiom from instead. Since base
classes have no name, unlike members, there cannot be two base classes of
the same type. This would prevent using the Ron's member idiom more than
once per enclosed type/initialization-parameter set. The
<code>UniqueID</code> template parameter gets around the problem, since
using different numbers makes the base classes different types. The
parameter has a default value of zero.</p>

<p>(<em>Author's Note:</em> these classes don't need to be used with
IOStreams. Should they be moved to the utility library?)</p>

<h3><a name="ron_syn">Synopsis</a></h3>

<blockquote><pre>
template &lt; typename MemberType, int UniqueID &gt;
class boost::nullary_rons_member
{
protected:
    nullary_rons_member();

    MemberType ron_;
};

template &lt; typename MemberType, typename InitializerType, int UniqueID
&gt;
class boost::unary_rons_member
{
protected:
    explicit unary_rons_member( InitializerType x );

    MemberType ron_;
};

template &lt; typename MemberType, typename InitializerType1,
           typename InitializerType2, int UniqueID &gt;
class boost::binary_rons_member
{
protected:
    binary_rons_member( InitializerType1 x, InitializerType2 y );

    MemberType ron_;
};
</pre></blockquote>

<h3><a name="ron_use">Usage</a></h3>

<blockquote><pre>
namespace boost
{

template &lt; typename Ch, class Tr &gt;
class basic_memstream
    : private binary_rons_member&lt; basic_membuf&lt;Ch, Tr&gt;, Ch,
::std::streamsize &gt;
    , public ::std::basic_iostream&lt;Ch, Tr&gt;
{
    typedef binary_rons_member&lt; basic_membuf&lt;Ch, Tr&gt;, Ch,
     ::std::streamsize &gt; pbase_type;
    typedef ::std::basic_iostream&lt;Ch, Tr&gt; base_type;

public:
    // Constructor
    basic_memstream( Ch *buffer, ::std::streamsize length );
};

//...

template &lt; typename Ch, class Tr &gt;
inline
basic_memstream&lt;Ch, Tr&gt;::basic_memstream
(
    Ch * buffer,
    ::std::streamsize length
)
    : pbase_type( buffer, length ), base_type(
&amp;this-&gt;pbase_type::ron_ )
{
}

}
</pre></blockquote>
//==========================================================================

-- 
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk