]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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_detail_has_type Introspecting an inner type] | |
9 | ||
10 | The TTI macro [macroref BOOST_TTI_HAS_TYPE] introspects | |
11 | a nested type of a class. | |
12 | ||
13 | The BOOST_TTI_HAS_TYPE macro takes a single parameter which is the name of | |
14 | an inner type whose existence the programmer wants to check. The | |
15 | macro generates a metafunction called 'has_type_'name_of_inner_type'. | |
16 | ||
17 | The main purpose of the generated metafunction is to check for the existence by | |
18 | name of the inner type. The metafunction can also be used to invoke an MPL lambda | |
19 | expression which is passed the inner type. One of the most common usages of the added | |
20 | functionality is to check whether or not the inner type is a typedef for another type. | |
21 | ||
22 | The metafunction is invoked by passing it the enclosing type | |
23 | to introspect. A second type may be passed to the | |
24 | metafunction, an MPL lambda expression taking the inner type | |
25 | and returning a boolean constant. | |
26 | ||
27 | The metafunction returns a single type called 'type', which is a | |
28 | boost::mpl::bool_. As a convenience the metafunction | |
29 | returns the value of this type directly as a compile time bool constant | |
30 | called 'value'. This value is true or false depending on whether the inner | |
31 | type exists or not. | |
32 | ||
33 | If a second optional type is passed, this type must be an MPL lambda expression | |
34 | and the expression will be invoked only if the inner type exists. In that case the | |
35 | metafunction returns true or false depending on whether the lambda expression returns | |
36 | true or false. If the inner type does not exist, the lambda expression, even if | |
37 | specified, is never invoked and the metafunction returns false. | |
38 | ||
39 | [heading Generating the metafunction] | |
40 | ||
41 | You generate the metafunction by invoking the macro with the name | |
42 | of an inner type: | |
43 | ||
44 | BOOST_TTI_HAS_TYPE(AType) | |
45 | ||
46 | generates a metafunction called 'has_type_AType' in the current scope. | |
47 | ||
48 | [heading Invoking the metafunction] | |
49 | ||
50 | You invoke the metafunction by instantiating the template with an enclosing | |
51 | type to introspect and, optionally, an MPL lambda expression. | |
52 | A return value called 'value' is a compile time bool constant. | |
53 | ||
54 | has_type_AType<Enclosing_Type>::value | |
55 | has_type_AType<Enclosing_Type,ALambdaExpression>::value | |
56 | ||
57 | [heading Examples] | |
58 | ||
59 | First we generate metafunctions for various inner type names: | |
60 | ||
61 | #include <boost/tti/has_type.hpp> | |
62 | ||
63 | BOOST_TTI_HAS_TYPE(MyTypeDef) | |
64 | BOOST_TTI_HAS_TYPE(AType) | |
65 | BOOST_TTI_HAS_TYPE(ATypeDef) | |
66 | BOOST_TTI_HAS_TYPE(MyType) | |
67 | ||
68 | Next let us create some user-defined types we want to introspect. | |
69 | ||
70 | struct Top | |
71 | { | |
72 | typedef int MyTypeDef; | |
73 | struct AType { }; | |
74 | }; | |
75 | struct Top2 | |
76 | { | |
77 | typedef long ATypeDef; | |
78 | struct MyType { }; | |
79 | }; | |
80 | ||
81 | Finally we invoke our metafunction and return our value. | |
82 | ||
83 | has_type_MyTypeDef<Top>::value; // true | |
84 | has_type_MyTypeDef<Top2>::value; // false | |
85 | ||
86 | has_type_AType<Top>::value; // true | |
87 | has_type_AType<Top2>::value; // false | |
88 | ||
89 | has_type_ATypeDef<Top>::value; // false | |
90 | has_type_ATypeDef<Top2>::value; // true | |
91 | ||
92 | has_type_MyType<Top>::value; // false | |
93 | has_type_MyType<Top2>::value; // true | |
94 | ||
95 | [heading Examples - using lambda expressions] | |
96 | ||
97 | We can further invoke our metafunction with a second type, | |
98 | which is an MPL lambda expression. | |
99 | ||
100 | An MPL lambda expression, an extremely useful technique in | |
101 | template metaprogramming, allows us to pass a metafunction to | |
102 | other metafunctions. The metafunction we pass can be in the form | |
103 | of a placeholder expression or a metafunction class. In our case | |
104 | the metafunction passed to our has_type_'name_of_inner_type' | |
105 | metafunction as a lambda expression must return a boolean constant | |
106 | expression. | |
107 | ||
108 | [heading Example - using a lambda expression with a placeholder expression] | |
109 | ||
110 | We will first illustrate the use of a lambda expression in the | |
111 | form of a placeholder expression being passed as the second template | |
112 | parameter to our has_type_'name_of_inner_type' metafunction. | |
113 | A popular and simple placeholder expression we can use is | |
114 | 'boost::is_same<_1,SomeType>' to check if the inner type found is a | |
115 | particular type. This is particularly useful when the inner type | |
116 | is a typedef for some other type. | |
117 | ||
118 | First we include some more header files and a using declaration | |
119 | for convenience. | |
120 | ||
121 | #include <boost/mpl/placeholders.hpp | |
122 | #include <boost/type_traits/is_same.hpp | |
123 | using namespace boost::mpl::placeholders; | |
124 | ||
125 | Next we invoke our metafunction: | |
126 | ||
127 | has_type_MyTypeDef<Top,boost::is_same<_1,int> >::value; // true | |
128 | has_type_MyTypeDef<Top,boost::is_same<_1,long> >::value; // false | |
129 | ||
130 | has_type_ATypeDef<Top2,boost::is_same<_1,int> >::value; // false | |
131 | has_type_ATypeDef<Top2,boost::is_same<_1,long> >::value; // true | |
132 | ||
133 | [heading Example - using a lambda expression with a metafunction class] | |
134 | ||
135 | We will next illustrate the use of a lambda expression in the | |
136 | form of a metafunction class being passed as the second template | |
137 | parameter to our has_type_'name_of_inner_type' metafunction. | |
138 | ||
139 | A metafunction class is a type which has a nested class template | |
140 | called 'apply'. For our metafunction class example we will check if the | |
141 | inner type is a built-in integer type. First let us write out | |
142 | metafunction class: | |
143 | ||
144 | #include <boost/type_traits/is_integral.hpp> | |
145 | ||
146 | class OurMetafunctionClass | |
147 | { | |
148 | template<class T> struct apply : | |
149 | boost::is_integral<T> | |
150 | { | |
151 | }; | |
152 | }; | |
153 | ||
154 | Now we can invoke our metafunction: | |
155 | ||
156 | has_type_MyTypeDef<Top,OurMetafunctionClass>::value; // true | |
157 | has_type_AType<Top,OurMetafunctionClass>::value; // false | |
158 | ||
159 | has_type_ATypeDef<Top2,OurMetafunctionClass>::value; // true | |
160 | has_type_MyType<Top2,OurMetafunctionClass>::value; // true | |
161 | ||
162 | [heading Metafunction re-use] | |
163 | ||
164 | The macro encodes only the name of the inner type for which | |
165 | we are searching and the fact that we are introspecting for | |
166 | an inner type within an enclosing type. | |
167 | ||
168 | Because of this, once we create our metafunction for | |
169 | introspecting an inner type by name, we can reuse the | |
170 | metafunction for introspecting any enclosing type, having | |
171 | any inner type, for that name. | |
172 | ||
173 | Furthermore since we have only encoded the name of the inner | |
174 | type for which we are introspecting, we can not only introspect | |
175 | for that inner type by name but add different lambda expressions | |
176 | to inspect that inner type for whatever we want to find out about | |
177 | it using the same metafunction. | |
178 | ||
179 | [endsect] |