]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/utility/doc/base_from_member.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / 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