1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 3.2//EN">
4 <title>Boost: Base-from-Member Idiom Documentation
</title>
7 <body bgcolor=
"white" link=
"blue" text=
"black" vlink=
"purple" alink=
"red">
8 <h1><img src=
"../../boost.png" alt=
"C++ Boost" align=
"middle"
9 width=
"277" height=
"86">Base-from-Member Idiom
</h1>
11 <p>The class template
<code>boost::base_from_member
</code> provides
12 a workaround for a class that needs to initialize a base class with a
13 member. The class template is in
<cite><a
14 href=
"../../boost/utility/base_from_member.hpp">boost/utility/base_from_member.hpp
</a></cite>
15 which is included in
<i><a href=
"../../boost/utility.hpp">boost/utility.hpp
</a></i>.
</p>
17 <p>There is test/example code in
<cite><a
18 href=
"base_from_member_test.cpp">base_from_member_test.cpp
</a></cite>.
</p>
20 <h2><a name=
"contents">Contents
</a></h2>
23 <li><a href=
"#contents">Contents
</a></li>
24 <li><a href=
"#rationale">Rationale
</a></li>
25 <li><a href=
"#synopsis">Synopsis
</a></li>
26 <li><a href=
"#usage">Usage
</a></li>
27 <li><a href=
"#example">Example
</a></li>
28 <li><a href=
"#credits">Credits
</a>
30 <li><a href=
"#contributors">Contributors
</a></li>
34 <h2><a name=
"rationale">Rationale
</a></h2>
36 <p>When developing a class, sometimes a base class needs to be
37 initialized with a member of the current class. As a na
ïve
41 #include
<streambuf
> <i>// for std::streambuf
</i>
42 #include
<ostream
> <i>// for std::ostream
</i>
45 : public std::streambuf
48 explicit fdoutbuf( int fd );
58 explicit fdostream( int fd )
59 : buf( fd ), std::ostream(
&buf )
65 <p>This is undefined because C++'s initialization order mandates that
66 the base class is initialized before the member it uses.
<a
67 href=
"http://www.moocat.org">R. Samuel Klatchko
</a> developed a way
68 around this by using the initialization order in his favor. Base
69 classes are intialized in order of declaration, so moving the desired
70 member to another base class, that is initialized before the desired
71 base class, can ensure proper initialization.
</p>
73 <p>A custom base class can be made for this idiom:
</p>
76 #include
<streambuf
> <i>// for std::streambuf
</i>
77 #include
<ostream
> <i>// for std::ostream
</i>
80 : public std::streambuf
83 explicit fdoutbuf( int fd );
87 struct fdostream_pbase
91 explicit fdostream_pbase( int fd )
97 : private fdostream_pbase
100 typedef fdostream_pbase pbase_type;
101 typedef std::ostream base_type;
104 explicit fdostream( int fd )
105 : pbase_type( fd ), base_type(
&sbuffer )
111 <p>Other projects can use similar custom base classes. The technique
112 is basic enough to make a template, with a sample template class in
113 this library. The main template parameter is the type of the enclosed
114 member. The template class has several (explicit) constructor member
115 templates, which implicitly type the constructor arguments and pass them
116 to the member. The template class uses implicit copy construction and
117 assignment, cancelling them if the enclosed member is non-copyable.
</p>
119 <p>Manually coding a base class may be better if the construction
120 and/or copying needs are too complex for the supplied template class,
121 or if the compiler is not advanced enough to use it.
</p>
123 <p>Since base classes are unnamed, a class cannot have multiple (direct)
124 base classes of the same type. The supplied template class has an
125 extra template parameter, an integer, that exists solely to provide type
126 differentiation. This parameter has a default value so a single use of a
127 particular member type does not need to concern itself with the integer.
</p>
129 <h2><a name=
"synopsis">Synopsis
</a></h2>
132 #ifndef BOOST_BASE_FROM_MEMBER_MAX_ARITY
133 #define BOOST_BASE_FROM_MEMBER_MAX_ARITY
10
136 template
< typename MemberType, int UniqueID =
0 >
137 class boost::base_from_member
144 template
< typename T1
>
145 explicit base_from_member( T1 x1 );
147 template
< typename T1, typename T2
>
148 base_from_member( T1 x1, T2 x2 );
152 template
< typename T1, typename T2, typename T3, typename T4,
153 typename T5, typename T6, typename T7, typename T8, typename T9,
155 base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
156 T8 x8, T9 x9, T10 x10 );
160 <p>The class template has a first template parameter
161 <var>MemberType
</var> representing the type of the based-member.
162 It has a last template parameter
<var>UniqueID
</var>, that is an
163 <code>int
</code>, to differentiate between multiple base classes that use
164 the same based-member type. The last template parameter has a default
165 value of zero if it is omitted. The class template has a protected
166 data member called
<var>member
</var> that the derived class can use
167 for later base classes (or itself).
</p>
169 <p>There is a default constructor and several constructor member
170 templates. These constructor templates can take as many arguments
171 (currently up to ten) as possible and pass them to a constructor of
172 the data member. Since C++ does not allow any way to explicitly state
173 the template parameters of a templated constructor, make sure that
174 the arguments are already close as possible to the actual type used in
175 the data member's desired constructor.
</p>
177 <p>The
<var>BOOST_BASE_FROM_MEMBER_MAX_ARITY
</var> macro constant specifies
178 the maximum argument length for the constructor templates. The constant
179 may be overridden if more (or less) argument configurations are needed. The
180 constant may be read for code that is expandable like the class template and
181 needs to maintain the same maximum size. (Example code would be a class that
182 uses this class template as a base class for a member with a flexible set of
185 <h2><a name=
"usage">Usage
</a></h2>
187 <p>With the starting example, the
<code>fdoutbuf
</code> sub-object needs
188 to be encapsulated in a base class that is inheirited before
189 <code>std::ostream
</code>.
</p>
192 #include
<boost/utility/base_from_member.hpp
>
194 #include
<streambuf
> <i>// for std::streambuf
</i>
195 #include
<ostream
> <i>// for std::ostream
</i>
198 : public std::streambuf
201 explicit fdoutbuf( int fd );
206 : private boost::base_from_member
<fdoutbuf
>
207 , public std::ostream
210 typedef boost::base_from_member
<fdoutbuf
> pbase_type;
211 typedef std::ostream base_type;
214 explicit fdostream( int fd )
215 : pbase_type( fd ), base_type(
&member )
221 <p>The base-from-member idiom is an implementation detail, so it
222 should not be visible to the clients (or any derived classes) of
223 <code>fdostream
</code>. Due to the initialization order, the
224 <code>fdoutbuf
</code> sub-object will get initialized before the
225 <code>std::ostream
</code> sub-object does, making the former
226 sub-object safe to use in the latter sub-object's construction. Since the
227 <code>fdoutbuf
</code> sub-object of the final type is the only sub-object
228 with the name
"member,
" that name can be used
229 unqualified within the final class.
</p>
231 <h2><a name=
"example">Example
</a></h2>
233 <p>The base-from-member class templates should commonly involve
234 only one base-from-member sub-object, usually for attaching a
235 stream-buffer to an I/O stream. The next example demonstrates how
236 to use multiple base-from-member sub-objects and the resulting
237 qualification issues.
</p>
240 #include
<boost/utility/base_from_member.hpp
>
242 #include
<cstddef
> <i>// for NULL
</i>
255 switcher( double, int * );
262 flow_regulator( switcher
&, switcher
& );
266 template
< unsigned Size
>
270 explicit fan( switcher );
275 : private boost::base_from_member
<an_int
>
276 , private boost::base_from_member
<switcher
>
277 , private boost::base_from_member
<switcher,
1>
278 , private boost::base_from_member
<switcher,
2>
279 , protected flow_regulator
280 , public fan
<6>
283 typedef boost::base_from_member
<an_int
> pbase0_type;
284 typedef boost::base_from_member
<switcher
> pbase1_type;
285 typedef boost::base_from_member
<switcher,
1> pbase2_type;
286 typedef boost::base_from_member
<switcher,
2> pbase3_type;
288 typedef flow_regulator base1_type;
289 typedef fan
<6> base2_type;
296 system::system( double x )
299 , pbase2_type( -
16,
&this-
>pbase0_type::member )
300 , pbase3_type( x, static_cast
<int *
>(NULL) )
301 , base1_type( pbase3_type::member, pbase1_type::member )
302 , base2_type( pbase2_type::member )
308 <p>The final class has multiple sub-objects with the name
309 "member,
" so any use of that name needs qualification by
310 a name of the appropriate base type. (Using
<code>typedef
</code>s
311 ease mentioning the base types.) However, the fix introduces a new
312 problem when a pointer is needed. Using the address operator with
313 a sub-object qualified with its class's name results in a pointer-to-member
314 (here, having a type of
<code>an_int boost::base_from_member
<an_int,
315 0> :: *
</code>) instead of a pointer to the member (having a type of
316 <code>an_int *
</code>). The new problem is fixed by qualifying the
317 sub-object with
"<code>this-
></code>,
" and is needed just
318 for pointers, and not for references or values.
</p>
320 <p>There are some argument conversions in the initialization. The
321 constructor argument for
<code>pbase0_type
</code> is converted from
322 <code>double
</code> to
<code>float
</code>. The first constructor
323 argument for
<code>pbase2_type
</code> is converted from
<code>int
</code>
324 to
<code>double
</code>. The second constructor argument for
325 <code>pbase3_type
</code> is a special case of necessary conversion; all
326 forms of the null-pointer literal in C++ also look like compile-time
327 integral expressions, so C++ always interprets such code as an integer
328 when it has overloads that can take either an integer or a pointer. The
329 last conversion is necessary for the compiler to call a constructor form
330 with the exact pointer type used in
<code>switcher
</code>'s constructor.
</p>
332 <h2><a name=
"credits">Credits
</a></h2>
334 <h3><a name=
"contributors">Contributors
</a></h3>
337 <dt><a href=
"../../people/ed_brey.htm">Ed Brey
</a>
338 <dd>Suggested some interface changes.
340 <dt><a href=
"http://www.moocat.org">R. Samuel Klatchko
</a> (
<a
341 href=
"mailto:rsk@moocat.org">rsk@moocat.org
</a>,
<a
342 href=
"mailto:rsk@brightmail.com">rsk@brightmail.com
</a>)
343 <dd>Invented the idiom of how to use a class member for initializing
346 <dt><a href=
"../../people/dietmar_kuehl.htm">Dietmar Kuehl
</a>
347 <dd>Popularized the base-from-member idiom in his
348 <a href=
"http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/">IOStream
351 <dt>Jonathan Turkanis
352 <dd>Supplied an implementation of generating the constructor templates that
353 can be controlled and automated with macros. The implementation uses
354 the
<a href=
"../preprocessor/index.html">Preprocessor library
</a>.
356 <dt><a href=
"../../people/daryle_walker.html">Daryle Walker
</a>
357 <dd>Started the library. Contributed the test file
<cite><a
358 href=
"base_from_member_test.cpp">base_from_member_test.cpp
</a></cite>.
363 <p>Revised:
28 August
2004</p>
365 <p>Copyright
2001,
2003,
2004 Daryle Walker. Use, modification, and distribution
366 are subject to the Boost Software License, Version
1.0. (See accompanying
367 file
<a href=
"../../LICENSE_1_0.txt">LICENSE_1_0.txt
</a> or a copy at
<<a
368 href=
"http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt
</a>>.)
</p>