]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/tti/doc/tti_nested_type.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / tti / doc / tti_nested_type.qbk
1 [/
2 (C) Copyright Edward Diener 2011,2012
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at
5 http://www.boost.org/LICENSE_1_0.txt).
6 ]
7
8 [section:tti_nested_type Nested Types]
9
10 Besides the functionality of the TTI library which queries whether some inner element
11 of a given name within a type exists, the library also includes functionality for
12 generating a nested type if it exists, else a marker type if it does not exist. By
13 marker type is meant a type either internally created by the library, with no functionality,
14 or designated by the end-user to represent the same idea.
15
16 First I will explain the syntax and use of this functionality and then the reason it exists in
17 the library.
18
19 The functionality is a metafunction created by the macro [macroref BOOST_TTI_MEMBER_TYPE].
20 The macro takes a single parameter, which is the name of a nested type. We will call this our
21 'named type'. The macro generates a metafunction called `member_type_'named_type'` which, passed
22 an enclosing type, returns the named type if it exists, else a marker type if it does not.
23
24 As with our other macros we can use the alternative form of the macro
25 [macroref BOOST_TTI_TRAIT_MEMBER_TYPE] to pass first the name of the metafunction
26 to be generated and then the name of the 'named type'. After that the functionality
27 of our resulting metafunction is exactly the same.
28
29 Its general explanation is given as:
30
31 [table:tbmacronested TTI Nested Type Macro Metafunction
32 [
33 [Inner Element]
34 [Macro]
35 [Template]
36 [Specific Header File]
37 ]
38 [
39 [Type]
40 [
41 [macroref BOOST_TTI_MEMBER_TYPE](name)
42 ]
43 [
44 `member_type_'name'`
45
46 class T = enclosing type
47 class U = (optional) marker type
48
49 returns = the type of 'name' if it exists, else a marker type, as the typedef 'type'.
50
51 The invoked metafunction also holds the marker type as the typedef 'boost_tti_marker_type'.
52 This is done for convenience so that the marker type does not have to be remembered.
53 ]
54 [[headerref boost/tti/member_type.hpp `member_type.hpp`]]
55 ]
56 ]
57
58 The marker type is purely optional. If not specified a type internal to the TTI library,
59 which has no functionality, is used. Unless there is a specific reason for the end-user
60 to provide his own marker type, he should let the TTI library use its own internal
61 marker type.
62
63 A simple example of this functionality would be:
64
65 #include <boost/tti/member_type.hpp>
66
67 BOOST_TTI_MEMBER_TYPE(ANamedType)
68
69 typedef typename member_type_ANamedType<EnclosingType>::type AType;
70
71 If type 'ANamedType' is a nested type of 'EnclosingType' then
72 AType is the same type as 'ANamedType', otherwise AType is a
73 marker type internal to the TTI library.
74
75 Now that we have explained the syntax of BOOST_TTI_MEMBER_TYPE
76 we can now answer the question of why this functionality to create
77 a 'type' exists when looking for a nested type of an enclosing type.
78
79 [heading The problem]
80
81 The metafunctions generated by the TTI macros all work with various types, whether in specifying
82 an enclosing type or in specifying the type of some inner element, which may also involve
83 types in the signature of that element, such as a parameter or return type of a function.
84 The C++ notation for a nested type, given an enclosing type 'T' and an inner type 'InnerType',
85 is 'T::InnerType'. If either the enclosing type 'T' does not exist, or the inner type 'InnerType'
86 does not exist within 'T', the expression 'T::InnerType' will give a compiler error if we attempt
87 to use it in our template instantiation of one of TTI's macro metafunctions.
88
89 This is a problem if we want to be able to introspect for the existence of inner elements
90 to an enclosing type without producing compiler errors. Of course if we absolutely know what
91 types we have and that a nested type exists, and these declarations are within our scope, we can
92 always use an expression like 'T::InnerType' without compiler error. But this is often not the
93 case when doing template programming since the type being passed to us at compile-time in a class
94 or function template is chosen at instantiation time and is created by the user of a template.
95
96 One solution to this is afforded by the library itself. Given an enclosing type 'T'
97 which we know must exist, either because it is a top-level type we know about or
98 it is passed to us in some template as a 'class T' or 'typename T', and given an inner type
99 named 'InnerType' whose existence we would like ascertain, we can use a `BOOST_TTI_HAS_TYPE(InnerType)`
100 macro and it's related `has_type_InnerType` metafunction to determine if the nested type 'InnerType'
101 exists. This solution is perfectly valid, and in conjunction with Boost MPL's selection metafunctions,
102 we can do compile-time selection to generate the correct template code.
103
104 However this does not scale that well syntactically if we need to drill down further
105 from a top-level enclosing type to a deeply nested type, or even to look for some deeply nested
106 type's inner elements. We are going to be generating a great deal of `boost::mpl::if_` and/or
107 `boost::mpl::eval_if` type selection statements to get to some final condition where we know we
108 can generate the compile-time code which we want.
109
110 [heading The solution]
111
112 The solution given by BOOST_TTI_MEMBER_TYPE is that we can create a type as the return
113 from our metafunction, which is the same type as a nested type if it exists or some other
114 marker type if it does not, and then work with that returned type without producing a
115 compiler error. If we had to use the 'T::InnerType' syntax to specify our type, where 'T' represents
116 out enclosing type and 'InnerType' our nested type, and there was no nested type 'InnerType' within the
117 enclosing type 'T, the compiler would give us an error immediately.
118
119 By using BOOST_TTI_MEMBER_TYPE we have a type to work with even when such a type
120 really does not exist. Naturally if the type does not exist, the type which we
121 have to work with, being a marker type, will generally not fulfill any other further functionality
122 we want from it. This is good and will normally produce the correct results in further uses of the type
123 when doing metafunction programming. Occasionally the TTI produced marker type, when our nested
124 type does not exist, is not sufficient for further metafunction programming. In that rare case the
125 end-user can produce his own marker type to be used if the nested type does not exist. In any case,
126 whether the nested type exists, whether the TTI default supplied marker type is used, or whether
127 an end-user marker type is used, template metaprogramming can continue without a compilation
128 problem. Furthermore this scales better than having to constant check for nested type existence
129 via BOOST_TTI_HAS_TYPE in complicated template metaprogramming code.
130
131 [heading Checking if the member type exists]
132
133 Once we use BOOST_TTI_MEMBER_TYPE to generate a nested type if it exists we will normally
134 use that type in further metafunction programming. Occasionally, given the type we generate,
135 we will want to ask if the type is really our nested type or the marker type instead. Essentially
136 we are asking if the type generated is the marker type or not. If it is the marker type, then
137 the type generated is not the nested type we had hoped for. If it is not the marker type, then
138 the type generated is the nested type we had hoped for. This is easy enough to do for the template
139 metaprogrammer but TTI makes it easier by providing either of two metafunctions to do this calculation.
140 These two metafunctions are 'boost::tti::valid_member_type' and 'boost::tti::valid_member_metafunction':
141
142 [table:existtbmacronested TTI Nested Type Macro Metafunction Existence
143 [
144 [Inner Element]
145 [Macro]
146 [Template]
147 [Specific Header File]
148 ]
149 [
150 [Type]
151 [None]
152 [
153 [classref boost::tti::valid_member_type]
154
155 class T = a type
156 class U = (optional) marker type
157
158 returns = true if the type exists, false if it does not.
159 'Existence' is determined by whether the type
160 does not equal the marker type of BOOST_TTI_MEMBER_TYPE.
161 ]
162 [[headerref boost/tti/member_type.hpp `member_type.hpp`]]
163 ]
164 [
165 [Type]
166 [None]
167 [
168 [classref boost::tti::valid_member_metafunction]
169
170 class T = a metafunction type
171
172 returns = true if the return 'type' of the metafunction exists,
173 false if it does not.'Existence' is determined by whether
174 the return 'type' does not equal the marker type of
175 BOOST_TTI_MEMBER_TYPE.
176 ]
177 [[headerref boost/tti/member_type.hpp `member_type.hpp`]]
178 ]
179 ]
180
181 In our first metafunction, 'boost::tti::valid_member_type', the first
182 parameter is the return 'type' from invoking the metafunction generated
183 by BOOST_TTI_MEMBER_TYPE. If when the metafunction was invoked a user-defined
184 marker type had been specified, then the second optional parameter is that
185 marker type, else it is not necessary to specify the optional second template
186 parameter. Since the marker type is saved as the nested type
187 boost::tti::marker_type once we invoke the metafunction generated by
188 BOOST_TTI_MEMBER_TYPE we can always use that as our second template parameter
189 to 'boost::tti::valid_member_type' if we like.
190
191 The second metafunction, boost::tti::valid_member_metafunction, makes the
192 process of passing our nested 'type' and our marker type a bit easier. Here
193 the single template parameter is the invoked metafunction generated by
194 BOOST_TTI_MEMBER_TYPE itself. It then picks out from the invoked metafunction
195 both the return 'type' and the nested boost::tti::marker_type to do the correct
196 calculation.
197
198 A simple example of this functionality would be:
199
200 #include <boost/tti/member_type.hpp>
201
202 struct UDMarkerType { };
203
204 BOOST_TTI_MEMBER_TYPE(ANamedType)
205
206 typedef member_type_ANamedType<EnclosingType> IMType;
207 typedef member_type_ANamedType<EnclosingType,UDMarkerType> IMTypeWithMarkerType;
208
209 then
210
211 boost::tti::valid_member_type<IMType::type>::value
212 boost::tti::valid_member_type<IMTypeWithMarkerType::type,IMTypeWithMarkerType::boost_tti_marker_type>::value
213
214 or
215
216 boost::tti::valid_member_metafunction<IMType>::value
217 boost::tti::valid_member_metafunction<IMTypeWithMarkerType>::value
218
219 gives us our compile-time result.
220
221 [heading An extended nested type example]
222
223 As an extended example, given a type T, let us create a metafunction where there is a nested type FindType
224 whose enclosing type is eventually T, as represented by the following structure:
225
226 struct T
227 {
228 struct AType
229 {
230 struct BType
231 {
232 struct CType
233 {
234 struct FindType
235 {
236 };
237 }
238 };
239 };
240 };
241
242 In our TTI code we first create a series of member type macros for each of our nested
243 types:
244
245 BOOST_TTI_MEMBER_TYPE(FindType)
246 BOOST_TTI_MEMBER_TYPE(AType)
247 BOOST_TTI_MEMBER_TYPE(BType)
248 BOOST_TTI_MEMBER_TYPE(CType)
249
250 Next we can create a typedef to reflect a nested type called FindType which has the relationship
251 as specified above by instantiating our macro metafunctions. We have to do this in the reverse
252 order of our hypothetical 'struct T' above since the metafunction `BOOST_TTI_MEMBER_TYPE` takes
253 its enclosing type as its template parameter.
254
255 typedef typename
256 member_type_FindType
257 <
258 typename member_type_CType
259 <
260 typename member_type_BType
261 <
262 typename member_type_AType
263 <
264 T
265 >::type
266 >::type
267 >::type
268 >::type MyFindType;
269
270 We can use the above typedef to pass the type as FindType
271 to one of our macro metafunctions. FindType may not actually exist but we will not generate
272 a compiler error when we use it. It will only generate, if it does not exist, an eventual
273 failure by having whatever metafunction uses such a type return a false value at compile-time.
274
275 As one example, let's ask whether FindType has a static member data called MyData of type 'int'.
276 We add:
277
278 BOOST_TTI_HAS_STATIC_MEMBER_DATA(MyData)
279
280 Next we create our metafunction:
281
282 has_static_member_data_MyData
283 <
284 MyFindType,
285 int
286 >
287
288 and use this in our metaprogramming code. Our metafunction now tells us whether the nested type
289 FindType has a static member data called MyData of type 'int', even if FindType does not actually
290 exist as we have specified it as a type. If we had tried to do this using normal C++ nested type
291 notation our metafunction code above would be:
292
293 has_static_member_data_MyData
294 <
295 typename T::AType::BType::CType::FindType,
296 int
297 >
298
299 But this fails with a compiler error if there is no such nested type, and
300 that is exactly what we do not want in our compile-time metaprogramming code.
301
302 In the above metafunction we are asking whether or not FindType has a static
303 member data element called 'MyData', and the result will be 'false' if either
304 FindType does not exist or if it does exist but does not have a static member data
305 of type 'int' called 'MyData'. In neither situation will we produce a compiler error.
306
307 We may also be interested in ascertaining whether the deeply nested
308 type 'FindType' actually exists. Our metafunction, using BOOST_TTI_MEMBER_TYPE
309 and repeating our macros from above, could be:
310
311 BOOST_TTI_MEMBER_TYPE(FindType)
312 BOOST_TTI_MEMBER_TYPE(AType)
313 BOOST_TTI_MEMBER_TYPE(BType)
314 BOOST_TTI_MEMBER_TYPE(CType)
315
316 BOOST_TTI_HAS_TYPE(FindType)
317
318 has_type_FindType
319 <
320 typename
321 member_type_CType
322 <
323 typename
324 member_type_BType
325 <
326 typename
327 member_type_AType
328 <
329 T
330 >::type
331 >::type
332 >::type
333 >
334
335 But this duplicates much of our code when we generated the 'MyFindType' typedef.
336 Instead we use the functionality already provided by 'boost::tti::valid_member_type'.
337 Using this functionality with our 'MyFindType' type above we create the nullary
338 metafunction:
339
340 boost::tti::valid_member_type
341 <
342 MyFindType
343 >
344
345 directly instead of replicating the same functionality with our 'has_type_FindType'
346 metafunction.
347
348 [endsect]