Improve vacpp support.
[boost.git] / boost / libs / utility / base_from_member.html
blob4dd70f432e757a17a8f934a54ed507fadb5e726f
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2 <html>
3 <head>
4 <title>Boost: Base-from-Member Idiom Documentation</title>
5 </head>
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>
22 <ul>
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>
29 <ul>
30 <li><a href="#contributors">Contributors</a></li>
31 </ul></li>
32 </ul>
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&iuml;ve
38 example:</p>
40 <blockquote><pre>
41 #include &lt;streambuf&gt; <i>// for std::streambuf</i>
42 #include &lt;ostream&gt; <i>// for std::ostream</i>
44 class fdoutbuf
45 : public std::streambuf
47 public:
48 explicit fdoutbuf( int fd );
49 //...
52 class fdostream
53 : public std::ostream
55 protected:
56 fdoutbuf buf;
57 public:
58 explicit fdostream( int fd )
59 : buf( fd ), std::ostream( &amp;buf )
61 //...
63 </pre></blockquote>
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>
75 <blockquote><pre>
76 #include &lt;streambuf&gt; <i>// for std::streambuf</i>
77 #include &lt;ostream&gt; <i>// for std::ostream</i>
79 class fdoutbuf
80 : public std::streambuf
82 public:
83 explicit fdoutbuf( int fd );
84 //...
87 struct fdostream_pbase
89 fdoutbuf sbuffer;
91 explicit fdostream_pbase( int fd )
92 : sbuffer( fd )
96 class fdostream
97 : private fdostream_pbase
98 , public std::ostream
100 typedef fdostream_pbase pbase_type;
101 typedef std::ostream base_type;
103 public:
104 explicit fdostream( int fd )
105 : pbase_type( fd ), base_type( &amp;sbuffer )
107 //...
109 </pre></blockquote>
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>
131 <blockquote><pre>
132 #ifndef BOOST_BASE_FROM_MEMBER_MAX_ARITY
133 #define BOOST_BASE_FROM_MEMBER_MAX_ARITY 10
134 #endif
136 template &lt; typename MemberType, int UniqueID = 0 &gt;
137 class boost::base_from_member
139 protected:
140 MemberType member;
142 base_from_member();
144 template&lt; typename T1 &gt;
145 explicit base_from_member( T1 x1 );
147 template&lt; typename T1, typename T2 &gt;
148 base_from_member( T1 x1, T2 x2 );
150 //...
152 template&lt; typename T1, typename T2, typename T3, typename T4,
153 typename T5, typename T6, typename T7, typename T8, typename T9,
154 typename T10 &gt;
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 );
158 </pre></blockquote>
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
183 constructors.)</p>
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>
191 <blockquote><pre>
192 #include &lt;boost/utility/base_from_member.hpp&gt;
194 #include &lt;streambuf&gt; <i>// for std::streambuf</i>
195 #include &lt;ostream&gt; <i>// for std::ostream</i>
197 class fdoutbuf
198 : public std::streambuf
200 public:
201 explicit fdoutbuf( int fd );
202 //...
205 class fdostream
206 : private boost::base_from_member&lt;fdoutbuf&gt;
207 , public std::ostream
209 // Helper typedef's
210 typedef boost::base_from_member&lt;fdoutbuf&gt; pbase_type;
211 typedef std::ostream base_type;
213 public:
214 explicit fdostream( int fd )
215 : pbase_type( fd ), base_type( &amp;member )
217 //...
219 </pre></blockquote>
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 &quot;member,&quot; 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>
239 <blockquote><pre>
240 #include &lt;boost/utility/base_from_member.hpp&gt;
242 #include &lt;cstddef&gt; <i>// for NULL</i>
244 struct an_int
246 int y;
248 an_int( float yf );
251 class switcher
253 public:
254 switcher();
255 switcher( double, int * );
256 //...
259 class flow_regulator
261 public:
262 flow_regulator( switcher &amp;, switcher &amp; );
263 //...
266 template &lt; unsigned Size &gt;
267 class fan
269 public:
270 explicit fan( switcher );
271 //...
274 class system
275 : private boost::base_from_member&lt;an_int&gt;
276 , private boost::base_from_member&lt;switcher&gt;
277 , private boost::base_from_member&lt;switcher, 1&gt;
278 , private boost::base_from_member&lt;switcher, 2&gt;
279 , protected flow_regulator
280 , public fan&lt;6&gt;
282 // Helper typedef's
283 typedef boost::base_from_member&lt;an_int&gt; pbase0_type;
284 typedef boost::base_from_member&lt;switcher&gt; pbase1_type;
285 typedef boost::base_from_member&lt;switcher, 1&gt; pbase2_type;
286 typedef boost::base_from_member&lt;switcher, 2&gt; pbase3_type;
288 typedef flow_regulator base1_type;
289 typedef fan&lt;6&gt; base2_type;
291 public:
292 system( double x );
293 //...
296 system::system( double x )
297 : pbase0_type( 0.2 )
298 , pbase1_type()
299 , pbase2_type( -16, &amp;this-&gt;pbase0_type::member )
300 , pbase3_type( x, static_cast&lt;int *&gt;(NULL) )
301 , base1_type( pbase3_type::member, pbase1_type::member )
302 , base2_type( pbase2_type::member )
304 //...
306 </pre></blockquote>
308 <p>The final class has multiple sub-objects with the name
309 &quot;member,&quot; 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&lt;an_int,
315 0&gt; :: *</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 &quot;<code>this-&gt;</code>,&quot; 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>
336 <dl>
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
344 a base class.
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
349 example classes</a>.
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>.
359 </dl>
361 <hr>
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 &lt;<a
368 href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>&gt;.)</p>
370 </body>
371 </html>