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