Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / utility / doc / base_from_member.qbk
1 [/
2   Copyright 2001, 2003, 2004, 2012 Daryle Walker.
3
4   Distributed under the Boost Software License, Version 1.0.
5
6   See accompanying file LICENSE_1_0.txt
7   or copy at http://boost.org/LICENSE_1_0.txt
8 ]
9
10 [article Base_From_Member
11     [quickbook 1.5]
12     [authors [Walker, Daryle]]
13     [copyright 2001, 2003, 2004, 2012 Daryle Walker]
14     [license
15         Distributed under the Boost Software License, Version 1.0.
16         (See accompanying file LICENSE_1_0.txt or copy at
17         [@http://www.boost.org/LICENSE_1_0.txt])
18     ]
19 ]
20
21 [section Rationale]
22
23 When developing a class, sometimes a base class needs to be initialized
24 with a member of the current class. As a na\u00EFve example:
25
26     #include <streambuf>  /* for std::streambuf */
27     #include <ostream>    /* for std::ostream */
28
29     class fdoutbuf
30       : public std::streambuf
31     {
32     public:
33         explicit fdoutbuf( int fd );
34         //...
35     };
36
37     class fdostream
38       : public std::ostream
39     {
40     protected:
41         fdoutbuf buf;
42     public:
43         explicit fdostream( int fd )
44           : buf( fd ), std::ostream( &buf ) {}
45         //...
46     };
47
48 This is undefined because C++'s initialization order mandates that the base
49 class is initialized before the member it uses. [@http://www.moocat.org R.
50 Samuel Klatchko] developed a way around this by using the initialization
51 order in his favor. Base classes are intialized in order of declaration, so
52 moving the desired member to another base class, that is initialized before
53 the desired base class, can ensure proper initialization.
54
55 A custom base class can be made for this idiom:
56
57     #include <streambuf>  /* for std::streambuf */
58     #include <ostream>    /* for std::ostream */
59
60     class fdoutbuf
61       : public std::streambuf
62     {
63     public:
64         explicit fdoutbuf( int fd );
65         //...
66     };
67
68     struct fdostream_pbase
69     {
70         fdoutbuf sbuffer;
71
72         explicit fdostream_pbase( int fd )
73           : sbuffer( fd ) {}
74     };
75
76     class fdostream
77       : private fdostream_pbase
78       , public std::ostream
79     {
80         typedef fdostream_pbase  pbase_type;
81         typedef std::ostream     base_type;
82
83     public:
84         explicit fdostream( int fd )
85           : pbase_type( fd ), base_type( &sbuffer ) {}
86         //...
87     };
88
89 Other projects can use similar custom base classes. The technique is basic
90 enough to make a template, with a sample template class in this library.
91 The main template parameter is the type of the enclosed member. The
92 template class has several (explicit) constructor member templates, which
93 implicitly type the constructor arguments and pass them to the member. The
94 template class uses implicit copy construction and assignment, cancelling
95 them if the enclosed member is non-copyable.
96
97 Manually coding a base class may be better if the construction and/or
98 copying needs are too complex for the supplied template class, or if the
99 compiler is not advanced enough to use it.
100
101 Since base classes are unnamed, a class cannot have multiple (direct) base
102 classes of the same type. The supplied template class has an extra template
103 parameter, an integer, that exists solely to provide type differentiation.
104 This parameter has a default value so a single use of a particular member
105 type does not need to concern itself with the integer.
106
107 [endsect]
108
109 [section Synopsis]
110
111     #include <type_traits>  /* exposition only */
112
113     #ifndef BOOST_BASE_FROM_MEMBER_MAX_ARITY
114     #define BOOST_BASE_FROM_MEMBER_MAX_ARITY  10
115     #endif
116
117     template < typename MemberType, int UniqueID = 0 >
118     class boost::base_from_member
119     {
120     protected:
121         MemberType  member;
122
123     #if ``['C++11 is in use]``
124         template< typename ...T >
125         explicit constexpr   base_from_member( T&& ...x )
126          noexcept( std::is_nothrow_constructible<MemberType, T...>::value );
127     #else
128         base_from_member();
129
130         template< typename T1 >
131         explicit  base_from_member( T1 x1 );
132
133         template< typename T1, typename T2 >
134         base_from_member( T1 x1, T2 x2 );
135
136         //...
137
138         template< typename T1, typename T2, typename T3, typename T4,
139          typename T5, typename T6, typename T7, typename T8, typename T9,
140          typename T10 >
141         base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
142          T8 x8, T9 x9, T10 x10 );
143     #endif
144     };
145
146     template < typename MemberType, int UniqueID >
147     class base_from_member<MemberType&, UniqueID>
148     {
149     protected:
150         MemberType& member;
151
152         explicit constexpr base_from_member( MemberType& x )
153             noexcept;
154     };
155
156 The class template has a first template parameter `MemberType` representing
157 the type of the based-member. It has a last template parameter `UniqueID`,
158 that is an `int`, to differentiate between multiple base classes that use
159 the same based-member type. The last template parameter has a default value
160 of zero if it is omitted. The class template has a protected data member
161 called `member` that the derived class can use for later base classes (or
162 itself).
163
164 If the appropriate features of C++11 are present, there will be a single
165 constructor template. It implements ['perfect forwarding] to the best
166 constructor call of `member` (if any). The constructor template is marked
167 both `constexpr` and `explicit`. The former will be ignored if the
168 corresponding inner constructor call (of `member`) does not have the marker.
169 The latter binds the other way; always taking effect, even when the inner
170 constructor call does not have the marker. The constructor template
171 propagates the `noexcept` status of the inner constructor call. (The
172 constructor template has a trailing parameter with a default value that
173 disables the template when its signature is too close to the signatures of
174 the automatically-defined non-template copy- and/or move-constructors of
175 `base_from_member`.)
176
177 On earlier-standard compilers, there is a default constructor and several
178 constructor member templates. These constructor templates can take as many
179 arguments (currently up to ten) as possible and pass them to a constructor
180 of the data member.
181
182 A specialization for member references offers a single constructor taking
183 a `MemberType&`, which is the only way to initialize a reference.
184
185 Since C++ does not allow any way to explicitly state the template parameters
186 of a templated constructor, make sure that the arguments are already close
187 as possible to the actual type used in the data member's desired constructor.
188 Explicit conversions may be necessary.
189
190 The `BOOST_BASE_FROM_MEMBER_MAX_ARITY` macro constant specifies the maximum
191 argument length for the constructor templates. The constant may be overridden
192 if more (or less) argument configurations are needed. The constant may be
193 read for code that is expandable like the class template and needs to
194 maintain the same maximum size. (Example code would be a class that uses
195 this class template as a base class for a member with a flexible set of
196 constructors.) This constant is ignored when C++11 features are present.
197
198 [endsect]
199
200 [section Usage]
201
202 With the starting example, the `fdoutbuf` sub-object needs to be
203 encapsulated in a base class that is inheirited before `std::ostream`.
204
205     #include <boost/utility/base_from_member.hpp>
206
207     #include <streambuf>  // for std::streambuf
208     #include <ostream>    // for std::ostream
209
210     class fdoutbuf
211       : public std::streambuf
212     {
213     public:
214         explicit fdoutbuf( int fd );
215         //...
216     };
217
218     class fdostream
219       : private boost::base_from_member<fdoutbuf>
220       , public std::ostream
221     {
222         // Helper typedef's
223         typedef boost::base_from_member<fdoutbuf>  pbase_type;
224         typedef std::ostream                        base_type;
225
226     public:
227         explicit fdostream( int fd )
228           : pbase_type( fd ), base_type( &member ){}
229         //...
230     };
231
232 The base-from-member idiom is an implementation detail, so it should not
233 be visible to the clients (or any derived classes) of `fdostream`. Due to
234 the initialization order, the `fdoutbuf` sub-object will get initialized
235 before the `std::ostream` sub-object does, making the former sub-object
236 safe to use in the latter sub-object's construction. Since the `fdoutbuf`
237 sub-object of the final type is the only sub-object with the name `member`
238 that name can be used unqualified within the final class.
239
240 [endsect]
241
242 [section Example]
243
244 The base-from-member class templates should commonly involve only one
245 base-from-member sub-object, usually for attaching a stream-buffer to an
246 I/O stream. The next example demonstrates how to use multiple
247 base-from-member sub-objects and the resulting qualification issues.
248
249     #include <boost/utility/base_from_member.hpp>
250
251     #include <cstddef>  /* for NULL */
252
253     struct an_int
254     {
255         int  y;
256
257         an_int( float yf );
258     };
259
260     class switcher
261     {
262     public:
263         switcher();
264         switcher( double, int * );
265         //...
266     };
267
268     class flow_regulator
269     {
270     public:
271         flow_regulator( switcher &, switcher & );
272         //...
273     };
274
275     template < unsigned Size >
276     class fan
277     {
278     public:
279         explicit fan( switcher );
280         //...
281     };
282
283     class system
284       : private boost::base_from_member<an_int>
285       , private boost::base_from_member<switcher>
286       , private boost::base_from_member<switcher, 1>
287       , private boost::base_from_member<switcher, 2>
288       , protected flow_regulator
289       , public fan<6>
290     {
291         // Helper typedef's
292         typedef boost::base_from_member<an_int>       pbase0_type;
293         typedef boost::base_from_member<switcher>     pbase1_type;
294         typedef boost::base_from_member<switcher, 1>  pbase2_type;
295         typedef boost::base_from_member<switcher, 2>  pbase3_type;
296
297         typedef flow_regulator  base1_type;
298         typedef fan<6>          base2_type;
299
300     public:
301         system( double x );
302         //...
303     };
304
305     system::system( double x )
306       : pbase0_type( 0.2 )
307       , pbase1_type()
308       , pbase2_type( -16, &this->pbase0_type::member.y )
309       , pbase3_type( x, static_cast<int *>(NULL) )
310       , base1_type( pbase3_type::member, pbase1_type::member )
311       , base2_type( pbase2_type::member )
312     {
313         //...
314     }
315
316 The final class has multiple sub-objects with the name `member`, so any
317 use of that name needs qualification by a name of the appropriate base
318 type. (Using `typedef`s ease mentioning the base types.) However, the fix
319 introduces a new problem when a pointer is needed. Using the address
320 operator with a sub-object qualified with its class's name results in a
321 pointer-to-member (here, having a type of `an_int boost::base_from_member<
322 an_int, 0> :: *`) instead of a pointer to the member (having a type of
323 `an_int *`). The new problem is fixed by qualifying the sub-object with
324 `this->` and is needed just for pointers, and not for references or values.
325
326 There are some argument conversions in the initialization. The constructor
327 argument for `pbase0_type` is converted from `double` to `float`. The first
328 constructor argument for `pbase2_type` is converted from `int` to `double`.
329 The second constructor argument for `pbase3_type` is a special case of
330 necessary conversion; all forms of the null-pointer literal in C++ (except
331 `nullptr` from C++11) also look like compile-time integral expressions, so
332 C++ always interprets such code as an integer when it has overloads that can
333 take either an integer or a pointer. The last conversion is necessary for the
334 compiler to call a constructor form with the exact pointer type used in
335 `switcher`'s constructor. (If C++11's `nullptr` is used, it still needs a
336 conversion if multiple pointer types can be accepted in a constructor call
337 but `std::nullptr_t` cannot.)
338
339 [endsect]
340
341 [section Acknowledgments]
342
343 * [@http://www.boost.org/people/ed_brey.htm Ed Brey] suggested some interface
344 changes.
345
346 * [@http://www.moocat.org R. Samuel Klatchko] ([@mailto:rsk@moocat.org
347 rsk@moocat.org], [@mailto:rsk@brightmail.com rsk@brightmail.com]) invented
348 the idiom of how to use a class member for initializing a base class.
349
350 * [@http://www.boost.org/people/dietmar_kuehl.htm Dietmar Kuehl] popularized the
351  base-from-member idiom in his [@http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/
352   IOStream example classes].
353
354 * Jonathan Turkanis supplied an implementation of generating the constructor
355 templates that can be controlled and automated with macros. The
356 implementation uses the [@../../../preprocessor/index.html Preprocessor library].
357
358 * [@http://www.boost.org/people/daryle_walker.html">Daryle Walker] started the
359 library. Contributed the test file [@../../base_from_member_test.cpp
360 base_from_member_test.cpp].
361
362 [endsect]
363