]>
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_template Introspecting an inner class template] | |
9 | ||
10 | [section:tti_detail_has_template_macro Using the BOOST_TTI_HAS_TEMPLATE macro] | |
11 | ||
12 | The TTI macro [macroref BOOST_TTI_HAS_TEMPLATE] introspects | |
13 | an inner class template of a class. The macro must specify, | |
14 | at the least, the name of the class template to introspect. | |
15 | ||
16 | [heading Two forms of introspection] | |
17 | ||
18 | There are two general forms of template introspection which can be used. | |
19 | The first is to find a class template with any number of only | |
20 | template type parameters ( template parameters starting with `class` | |
21 | or `typename` ). In this form only the name of the class template | |
22 | needs to be specified when invoking the macro. We will call this form | |
23 | of the macro the `template type parameters` form. An example of a class | |
24 | template of this form which could be successfully introspected would be: | |
25 | ||
26 | template<class X,typename Y,class Z,typename T> class AClassTemplate { /* etc. */ }; | |
27 | ||
28 | The second is to find a class template with specific template parameters. | |
29 | In this form both the name of the class template and the template parameters | |
30 | are passed to the macro. | |
31 | ||
32 | We will call this form of the macro the `specific parameters` form. An example | |
33 | of a class template of this form which could be successfully introspected would be: | |
34 | ||
35 | template<class X, template<class> class Y, int Z> BClassTemplate { /* etc. */ }; | |
36 | ||
37 | When using the specific form of the macro, there are two things which | |
38 | need to be understood when passing the template parameters to the macro. | |
39 | First, the actual names of the template parameters passed are irrelevant. | |
40 | They can be left out completely or be different from the names in the | |
41 | nested class template itself. Second, the use of 'typename' or 'class', | |
42 | when referring to a template type parameter, is completely interchangeable, | |
43 | as it is in the actual class template itself. | |
44 | ||
45 | [heading Variadic and non-variadic macro usage] | |
46 | ||
47 | When using the BOOST_TTI_HAS_TEMPLATE macro we distinguish between compilers | |
48 | supporting variadic macros or not supporting variadic macros. | |
49 | ||
50 | The programmer can always tell whether or not the compiler | |
51 | supports variadic macros by checking the value of the macro | |
52 | BOOST_PP_VARIADIC after including the necessary header file | |
53 | `boost/tti/has_template.hpp` in order to use the BOOST_TTI_TEMPLATE | |
54 | macro. A value of 1 indicates the compiler supports variadic macros | |
55 | while a value of 0 indicates the compiler does not support variadic | |
56 | macros. | |
57 | ||
58 | Modern C++ compilers, in supporting the latest C++11 standard, | |
59 | normally support variadic macros. Even before the latest C++11 standard | |
60 | a number of C++ compilers already supported variadic macros. If you feel | |
61 | your compiler supports variadic macros and BOOST_PP_VARIADIC is 0 even | |
62 | after including `boost/tti/has_template.hpp`, you can predefine BOOST_PP_VARIADIC | |
63 | to 1 before including `boost/tti/has_template.hpp`. | |
64 | ||
65 | [heading Non-variadic macro usage] | |
66 | ||
67 | We start with syntax for compilers not supporting variadic macros since this | |
68 | syntax can also be used by compilers which do support variadic macros. The | |
69 | form for non-variadic macros always takes two macro parameters. The first | |
70 | macro parameter is always the name of the class template you are trying to | |
71 | introspect. | |
72 | ||
73 | The second macro parameter, when using the `specific parameters` form of the | |
74 | macro, is the template parameters in the form of a Boost preprocessor library | |
75 | array data type. When using the `template type parameters` form of the macro | |
76 | the second macro parameter is BOOST_PP_NIL. If the second parameter is neither | |
77 | a Boost preprocessor library array data type or BOOS_PP_NIL you will get a | |
78 | compiler error if your compiler only supports non-variadic macros. | |
79 | ||
80 | The non-variadic macro form for introspecting the class templates above | |
81 | using the `template type parameters` form would be: | |
82 | ||
83 | BOOST_TTI_TEMPLATE(AClassTemplate,BOOST_PP_NIL) | |
84 | BOOST_TTI_TEMPLATE(BClassTemplate,BOOST_PP_NIL) | |
85 | ||
86 | Invoking the metafunction in the second case would always fail since the | |
87 | BClassTemplate does not have all template type parameters. | |
88 | ||
89 | The non-variadic macro form for introspecting the class templates above | |
90 | using the `specific parameters` form would be: | |
91 | ||
92 | BOOST_TTI_TEMPLATE(AClassTemplate,(4,(class,typename,class,typename))) | |
93 | BOOST_TTI_TEMPLATE(BClassTemplate,(3,(class, template<class> class, int))) | |
94 | ||
95 | You need to be careful using the non-variadic `specific parameters` form | |
96 | to specify the correct number of array parameters. This can sometimes be | |
97 | tricky if you have a template template parameter, or a | |
98 | non-type template parameter which has parentheses | |
99 | surrounding part of the type specification. In the latter case, | |
100 | when parentheses surround a comma ( ',' ), do not count that as | |
101 | creating another Boost PP array token. Two examples: | |
102 | ||
103 | template<void (*FunctionPointer)(int,long)> class CClassTemplate { /* etc. */ }; | |
104 | template<template<class,class> class T> class DClassTemplate { /* etc. */ }; | |
105 | ||
106 | BOOST_TTI_TEMPLATE(CClassTemplate,(1,(void (*)(int,long)))) | |
107 | BOOST_TTI_TEMPLATE(DClassTemplate,(2,(template<class,class> class))) | |
108 | ||
109 | In the case of using the macro to introspect CClassTemplate the number of | |
110 | Boost PP array parameters is 1, even though there is a comma separating | |
111 | the tokens in `void (*FunctionPointer)(int,long)`. This is because the | |
112 | comma is within parentheses. | |
113 | ||
114 | In the case of using the macro to introspect DClassTemplate the number of | |
115 | Boost PP array parameters is 2, because there is a comma separating the | |
116 | tokens in `template<class,class> class T`. | |
117 | ||
118 | [heading Variadic macro usage] | |
119 | ||
120 | Having the ability to use variadic macros makes the syntax for using | |
121 | BOOST_TTI_TEMPLATE easier to specify in both the `template type parameters` | |
122 | form and the `specific parameters` form of using the macro. | |
123 | This is because variadic macros can take a variable number of parameters. | |
124 | When using the variadic macro form the first macro parameter is always the name | |
125 | of the class template you are trying to introspect. You only specify | |
126 | further parameters when using the `specific parameters` form of the macro, | |
127 | in which case the further parameters to the macro are the specific template | |
128 | parameters. | |
129 | ||
130 | Introspecting the first class template above using the | |
131 | `template type parameters` form the variadic macro would be: | |
132 | ||
133 | BOOST_TTI_TEMPLATE(AClassTemplate) | |
134 | ||
135 | Introspecting the other class templates above using the | |
136 | `specific parameters` form the variadic macros would be: | |
137 | ||
138 | BOOST_TTI_TEMPLATE(BClassTemplate,class,template<class> class, int) | |
139 | BOOST_TTI_TEMPLATE(CClassTemplate,void (*)(int,long)) | |
140 | BOOST_TTI_TEMPLATE(DClassTemplate,template<class,class> class) | |
141 | ||
142 | Here we have no problem with counting the number of tuple tokens | |
143 | for the Boost PP array, nor do we have to specify BOOST_PP_NIL if | |
144 | we are using the `template type parameters` form. Also for the | |
145 | specific parameters form we simply use the template parameters as | |
146 | the remaining tokens of the variadic macro. | |
147 | ||
148 | [heading The resulting metafunction] | |
149 | ||
150 | Using either form of the macro, whether using variadic or non-variadic | |
151 | syntax, the macro generates a metafunction called | |
152 | 'has_template_'name_of_inner_class_template'. | |
153 | ||
154 | The metafunction can be invoked by passing it the enclosing type | |
155 | to introspect. | |
156 | ||
157 | The metafunction returns a single type called 'type', which is a | |
158 | boost::mpl::bool_. As a convenience the metafunction returns the | |
159 | value of this type directly as a compile time bool constant | |
160 | called 'value'. This is true or false depending on whether the inner | |
161 | class template exists or not. | |
162 | ||
163 | [endsect] | |
164 | ||
165 | [section:tti_detail_has_template_metafunction Using the has_template_(xxx) metafunction] | |
166 | ||
167 | [heading Generating the metafunction] | |
168 | ||
169 | You generate the metafunction by invoking the macro with the name | |
170 | of an inner class template: | |
171 | ||
172 | // `template type parameters` form | |
173 | ||
174 | BOOST_TTI_HAS_TEMPLATE(AClassTemplate,BOOST_PP_NIL) // non-variadic macro | |
175 | BOOST_TTI_HAS_TEMPLATE(AClassTemplate) // variadic macro | |
176 | ||
177 | // `specific parameters` form | |
178 | ||
179 | BOOST_TTI_HAS_TEMPLATE(AClassTemplate,(2,(class,int))) // non-variadic macro | |
180 | BOOST_TTI_HAS_TEMPLATE(AClassTemplate,class,int) // variadic macro | |
181 | ||
182 | generates a metafunction called 'has_template_AClassTemplate' in the current scope. | |
183 | ||
184 | If you want to introspect the same class template name using both the | |
185 | `template type parameters` form and the `specific parameters` form | |
186 | you will have the problem that you will be generating a metafunction | |
187 | of the same name and violating the C++ ODR rule. In this particular | |
188 | case you can use the alternate BOOST_TTI_TRAIT_HAS_TEMPLATE macro | |
189 | to name the particular metafunction which will be generated. | |
190 | ||
191 | [heading Invoking the metafunction] | |
192 | ||
193 | You invoke the metafunction by instantiating the template with an enclosing | |
194 | type to introspect. A return value called 'value' is a compile time bool constant. | |
195 | ||
196 | has_template_AType<Enclosing_Type>::value | |
197 | ||
198 | [heading Examples] | |
199 | ||
200 | First we generate metafunctions for various inner class template names: | |
201 | ||
202 | #include <boost/tti/has_template.hpp> | |
203 | ||
204 | // Using variadic macro, `template type parameters` | |
205 | ||
206 | BOOST_TTI_HAS_TEMPLATE(Template1) | |
207 | BOOST_TTI_HAS_TEMPLATE(Template2) | |
208 | BOOST_TTI_HAS_TEMPLATE(Template3) | |
209 | BOOST_TTI_HAS_TEMPLATE(Template4) | |
210 | BOOST_TTI_HAS_TEMPLATE(Template5) | |
211 | ||
212 | // or using non-variadic macro, `template type parameters` | |
213 | ||
214 | BOOST_TTI_HAS_TEMPLATE(Template1,BOOST_PP_NIL) | |
215 | BOOST_TTI_HAS_TEMPLATE(Template2,BOOST_PP_NIL) | |
216 | BOOST_TTI_HAS_TEMPLATE(Template3,BOOST_PP_NIL) | |
217 | BOOST_TTI_HAS_TEMPLATE(Template4,BOOST_PP_NIL) | |
218 | BOOST_TTI_HAS_TEMPLATE(Template5,BOOST_PP_NIL) | |
219 | ||
220 | // Using variadic macro, `specific parameters` | |
221 | ||
222 | BOOST_TTI_HAS_TEMPLATE(Template6,class,int) | |
223 | BOOST_TTI_HAS_TEMPLATE(Template7,typename,template<class,class> struct,long) | |
224 | BOOST_TTI_HAS_TEMPLATE(Template8,double,typename) | |
225 | BOOST_TTI_HAS_TEMPLATE(Template9,typename,class,typename,class,typename,short) | |
226 | ||
227 | // or using non-variadic macro, `specific parameters` | |
228 | ||
229 | BOOST_TTI_HAS_TEMPLATE(Template6,(2,(class,int))) | |
230 | BOOST_TTI_HAS_TEMPLATE(Template7,(4,(typename,template<class,class> struct,long))) | |
231 | BOOST_TTI_HAS_TEMPLATE(Template8,(2,(double,typename))) | |
232 | BOOST_TTI_HAS_TEMPLATE(Template9,(6,(typename,class,typename,class,typename,short))) | |
233 | ||
234 | Next let us create some user-defined types we want to introspect. | |
235 | ||
236 | struct Top | |
237 | { | |
238 | template <class X> struct Template1 { }; | |
239 | template <typename A,typename B,typename C> class Template2 { }; | |
240 | template <typename A,typename B,typename C,int D> class Template3 { }; | |
241 | }; | |
242 | struct Top2 | |
243 | { | |
244 | template <typename A,typename B,typename C,class D> class Template3 { }; | |
245 | template <class X,typename Y> struct Template4 { }; | |
246 | template <typename A,class B,typename C,class D,typename E> class Template5 { }; | |
247 | }; | |
248 | struct Top3 | |
249 | { | |
250 | template <class X,int Y> struct Template6 { }; | |
251 | template <typename A,template<class,class> struct B,long C> class Template7 { }; | |
252 | }; | |
253 | struct Top4 | |
254 | { | |
255 | template <double X,typename Y> struct Template8 { }; | |
256 | template <typename A,class B,typename C,class D,typename E,short F> class Template9 { }; | |
257 | }; | |
258 | ||
259 | Finally we invoke our metafunction and return our value. | |
260 | This all happens at compile time, and can be used by | |
261 | programmers doing compile time template metaprogramming. | |
262 | ||
263 | has_template_Template1<Top>::value; // true | |
264 | has_template_Template1<Top2>::value; // false | |
265 | ||
266 | has_template_Template2<Top>::value; // true | |
267 | has_template_Template2<Top2>::value; // false | |
268 | ||
269 | has_template_Template3<Top>::value; // false, not all typename/class template parameters | |
270 | has_template_Template3<Top2>::value; // true | |
271 | ||
272 | has_template_Template4<Top>::value; // false | |
273 | has_template_Template4<Top2>::value; // true | |
274 | ||
275 | has_template_Template5<Top>::value; // false | |
276 | has_template_Template5<Top2>::value; // true | |
277 | ||
278 | has_template_Template6<Top3>::value; // true | |
279 | has_template_Template6<Top4>::value; // false | |
280 | ||
281 | has_template_Template7<Top3>::value; // true | |
282 | has_template_Template7<Top4>::value; // false | |
283 | ||
284 | has_template_Template8<Top3>::value; // false | |
285 | has_template_Template8<Top4>::value; // true | |
286 | ||
287 | has_template_Template9<Top3>::value; // false | |
288 | has_template_Template9<Top4>::value; // true | |
289 | ||
290 | [heading Metafunction re-use] | |
291 | ||
292 | The macro encodes the name of the inner class template for | |
293 | which we are searching, the fact that we are introspecting for | |
294 | a class template within an enclosing type, and optionally the | |
295 | template parameters for that class template. | |
296 | ||
297 | Once we create our metafunction for introspecting an inner class | |
298 | template by name, we can reuse the metafunction for introspecting | |
299 | any enclosing type, having any inner class template, for that name. | |
300 | ||
301 | However we need to understand that we are restricted in our reuse | |
302 | of the metafunction by whether we originally use the template type | |
303 | parameters form or the specific form. In either case we are always | |
304 | introspecting an inner class template which matches that form. | |
305 | In the case of the template type parameters form, any inner class | |
306 | template for which we are introspecting must have all template type | |
307 | parameters, as well as the correct name. In the case of the specific | |
308 | parameters form, any inner class template for which we are | |
309 | introspecting must have template parameters which match the specific | |
310 | template parameters passed to the macro, as well as the correct name. | |
311 | ||
312 | [endsect] | |
313 | ||
314 | [endsect] |