summaryrefslogtreecommitdiff
path: root/libs/tti/doc/tti_detail_has_template.qbk
blob: 837c25ee39d91b3944fa2ffd3d39edd5c97b7a61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
[/ 
  (C) Copyright Edward Diener 2011,2012
  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE_1_0.txt or copy at
  http://www.boost.org/LICENSE_1_0.txt).
]

[section:tti_detail_has_template Introspecting an inner class template]

[section:tti_detail_has_template_macro Using the BOOST_TTI_HAS_TEMPLATE macro]

The TTI macro [macroref BOOST_TTI_HAS_TEMPLATE] introspects
an inner class template of a class. The macro must specify,
at the least, the name of the class template to introspect.

[heading Two forms of introspection]
 
There are two general forms of template introspection which can be used.
The first is to find a class template with any number of only 
template type parameters ( template parameters starting with `class` 
or `typename` ). In this form only the name of the class template 
needs to be specified when invoking the macro. We will call this form
of the macro the `template type parameters` form. An example of a class 
template of this form which could be successfully introspected would be:

 template<class X,typename Y,class Z,typename T> class AClassTemplate { /* etc. */ };

The second is to find a class template with specific template parameters. 
In this form both the name of the class template and the template parameters 
are passed to the macro. 

We will call this form of the macro the `specific parameters` form. An example 
of a class template of this form which could be successfully introspected would be:

 template<class X, template<class> class Y, int Z> BClassTemplate { /* etc. */ };
 
When using the specific form of the macro, there are two things which 
need to be understood when passing the template parameters to the macro.
First, the actual names of the template parameters passed are irrelevant.
They can be left out completely or be different from the names in the 
nested class template itself. Second, the use of 'typename' or 'class',
when referring to a template type parameter, is completely interchangeable,
as it is in the actual class template itself.
 
[heading Variadic and non-variadic macro usage]
 
When using the BOOST_TTI_HAS_TEMPLATE macro we distinguish between compilers 
supporting variadic macros or not supporting variadic macros.

The programmer can always tell whether or not the compiler 
supports variadic macros by checking the value of the macro 
BOOST_PP_VARIADIC after including the necessary header file 
`boost/tti/has_template.hpp` in order to use the BOOST_TTI_TEMPLATE
macro. A value of 1 indicates the compiler supports variadic macros
while a value of 0 indicates the compiler does not support variadic 
macros.

Modern C++ compilers, in supporting the latest  C++11 standard, 
normally support variadic macros. Even before the latest C++11 standard 
a number of C++ compilers already supported variadic macros. If you feel
your compiler supports variadic macros and BOOST_PP_VARIADIC is 0 even
after including `boost/tti/has_template.hpp`, you can predefine BOOST_PP_VARIADIC
to 1 before including `boost/tti/has_template.hpp`.

[heading Non-variadic macro usage]

We start with syntax for compilers not supporting variadic macros since this
syntax can also be used by compilers which do support variadic macros. The 
form for non-variadic macros always takes two macro parameters. The first 
macro parameter is always the name of the class template you are trying to 
introspect.

The second macro parameter, when using the `specific parameters` form of the 
macro, is the template parameters in the form of a Boost preprocessor library 
array data type. When using the `template type parameters` form of the macro
the second macro parameter is BOOST_PP_NIL. If the second parameter is neither
a Boost preprocessor library array data type or BOOS_PP_NIL you will get a 
compiler error if your compiler only supports non-variadic macros.

The non-variadic macro form for introspecting the class templates above 
using the `template type parameters` form would be:

 BOOST_TTI_TEMPLATE(AClassTemplate,BOOST_PP_NIL)
 BOOST_TTI_TEMPLATE(BClassTemplate,BOOST_PP_NIL)
 
Invoking the metafunction in the second case would always fail since the 
BClassTemplate does not have all template type parameters.
 
The non-variadic macro form for introspecting the class templates above 
using the `specific parameters` form would be:

 BOOST_TTI_TEMPLATE(AClassTemplate,(4,(class,typename,class,typename)))
 BOOST_TTI_TEMPLATE(BClassTemplate,(3,(class, template<class> class, int)))
 
You need to be careful using the non-variadic `specific parameters` form
to specify the correct number of array parameters. This can sometimes be 
tricky if you have a template template parameter, or a 
non-type template parameter which has parentheses 
surrounding part of the type specification. In the latter case,
when parentheses surround a comma ( ',' ), do not count that as
creating another Boost PP array token. Two examples:

 template<void (*FunctionPointer)(int,long)> class CClassTemplate { /* etc. */ };
 template<template<class,class> class T> class DClassTemplate { /* etc. */ };
 
 BOOST_TTI_TEMPLATE(CClassTemplate,(1,(void (*)(int,long))))
 BOOST_TTI_TEMPLATE(DClassTemplate,(2,(template<class,class> class)))
 
In the case of using the macro to introspect CClassTemplate the number of
Boost PP array parameters is 1, even though there is a comma separating
the tokens in `void (*FunctionPointer)(int,long)`. This is because the 
comma is within parentheses.

In the case of using the macro to introspect DClassTemplate the number of
Boost PP array parameters is 2, because there is a comma separating the 
tokens in `template<class,class> class T`.
 
[heading Variadic macro usage]

Having the ability to use variadic macros makes the syntax for using 
BOOST_TTI_TEMPLATE easier to specify in both the `template type parameters`
form and the `specific parameters` form of using the macro.
This is because variadic macros can take a variable number of parameters. 
When using the variadic macro form the first macro parameter is always the name 
of the class template you are trying to introspect. You only specify 
further parameters when using the `specific parameters` form of the macro, 
in which case the further parameters to the macro are the specific template 
parameters.

Introspecting the first class template above using the 
`template type parameters` form the variadic macro would be:

 BOOST_TTI_TEMPLATE(AClassTemplate)
 
Introspecting the other class templates above using the 
`specific parameters` form the variadic macros would be:

 BOOST_TTI_TEMPLATE(BClassTemplate,class,template<class> class, int)
 BOOST_TTI_TEMPLATE(CClassTemplate,void (*)(int,long))
 BOOST_TTI_TEMPLATE(DClassTemplate,template<class,class> class)
 
Here we have no problem with counting the number of tuple tokens 
for the Boost PP array, nor do we have to specify BOOST_PP_NIL if 
we are using the `template type parameters` form. Also for the 
specific parameters form we simply use the template parameters as 
the remaining tokens of the variadic macro.
 
[heading The resulting metafunction]

Using either form of the macro, whether using variadic or non-variadic 
syntax, the macro generates a metafunction called 
"has_template_'name_of_inner_class_template'".

The metafunction can be invoked by passing it the enclosing type 
to introspect.

The metafunction returns a single type called 'type', which is a 
boost::mpl::bool_. As a convenience the metafunction returns the 
value of this type directly as a compile time bool constant 
called 'value'. This is true or false depending on whether the inner 
class template exists or not.

[endsect]

[section:tti_detail_has_template_metafunction Using the has_template_(xxx) metafunction]

[heading Generating the metafunction]

You generate the metafunction by invoking the macro with the name 
of an inner class template:

  // `template type parameters` form

  BOOST_TTI_HAS_TEMPLATE(AClassTemplate,BOOST_PP_NIL) // non-variadic macro
  BOOST_TTI_HAS_TEMPLATE(AClassTemplate)              // variadic macro
  
  // `specific parameters` form
  
  BOOST_TTI_HAS_TEMPLATE(AClassTemplate,(2,(class,int))) // non-variadic macro
  BOOST_TTI_HAS_TEMPLATE(AClassTemplate,class,int)       // variadic macro
  
generates a metafunction called 'has_template_AClassTemplate' in the current scope.
   
If you want to introspect the same class template name using both the 
`template type parameters` form and the `specific parameters` form
you will have the problem that you will be generating a metafunction
of the same name and violating the C++ ODR rule. In this particular
case you can use the alternate BOOST_TTI_TRAIT_HAS_TEMPLATE macro
to name the particular metafunction which will be generated.

[heading Invoking the metafunction]

You invoke the metafunction by instantiating the template with an enclosing 
type to introspect. A return value called 'value' is a compile time bool constant.

  has_template_AType<Enclosing_Type>::value
  
[heading Examples]

First we generate metafunctions for various inner class template names:

 #include <boost/tti/has_template.hpp>
 
 // Using variadic macro, `template type parameters`
 
 BOOST_TTI_HAS_TEMPLATE(Template1)
 BOOST_TTI_HAS_TEMPLATE(Template2)
 BOOST_TTI_HAS_TEMPLATE(Template3)
 BOOST_TTI_HAS_TEMPLATE(Template4)
 BOOST_TTI_HAS_TEMPLATE(Template5)
 
 // or using non-variadic macro, `template type parameters`
 
 BOOST_TTI_HAS_TEMPLATE(Template1,BOOST_PP_NIL)
 BOOST_TTI_HAS_TEMPLATE(Template2,BOOST_PP_NIL)
 BOOST_TTI_HAS_TEMPLATE(Template3,BOOST_PP_NIL)
 BOOST_TTI_HAS_TEMPLATE(Template4,BOOST_PP_NIL)
 BOOST_TTI_HAS_TEMPLATE(Template5,BOOST_PP_NIL)
 
 // Using variadic macro, `specific parameters`
 
 BOOST_TTI_HAS_TEMPLATE(Template6,class,int)
 BOOST_TTI_HAS_TEMPLATE(Template7,typename,template<class,class> struct,long)
 BOOST_TTI_HAS_TEMPLATE(Template8,double,typename)
 BOOST_TTI_HAS_TEMPLATE(Template9,typename,class,typename,class,typename,short)
 
 // or using non-variadic macro, `specific parameters`
 
 BOOST_TTI_HAS_TEMPLATE(Template6,(2,(class,int)))
 BOOST_TTI_HAS_TEMPLATE(Template7,(4,(typename,template<class,class> struct,long)))
 BOOST_TTI_HAS_TEMPLATE(Template8,(2,(double,typename)))
 BOOST_TTI_HAS_TEMPLATE(Template9,(6,(typename,class,typename,class,typename,short)))
 
Next let us create some user-defined types we want to introspect. 

 struct Top
   {
   template <class X> struct Template1 { };
   template <typename A,typename B,typename C> class Template2 { };
   template <typename A,typename B,typename C,int D> class Template3 { };
   };
 struct Top2
   {
   template <typename A,typename B,typename C,class D> class Template3 { };
   template <class X,typename Y> struct Template4 { };
   template <typename A,class B,typename C,class D,typename E> class Template5 { };
   };
 struct Top3
   {
   template <class X,int Y> struct Template6 { };
   template <typename A,template<class,class> struct B,long C> class Template7 { };
   };
 struct Top4
   {
   template <double X,typename Y> struct Template8 { };
   template <typename A,class B,typename C,class D,typename E,short F> class Template9 { };
   };
   
Finally we invoke our metafunction and return our value.
This all happens at compile time, and can be used by 
programmers doing compile time template metaprogramming.
  
 has_template_Template1<Top>::value; // true
 has_template_Template1<Top2>::value; // false
 
 has_template_Template2<Top>::value; // true
 has_template_Template2<Top2>::value; // false
 
 has_template_Template3<Top>::value; // false, not all typename/class template parameters
 has_template_Template3<Top2>::value; // true
 
 has_template_Template4<Top>::value; // false
 has_template_Template4<Top2>::value; // true
 
 has_template_Template5<Top>::value; // false
 has_template_Template5<Top2>::value; // true
  
 has_template_Template6<Top3>::value; // true
 has_template_Template6<Top4>::value; // false
 
 has_template_Template7<Top3>::value; // true
 has_template_Template7<Top4>::value; // false
 
 has_template_Template8<Top3>::value; // false
 has_template_Template8<Top4>::value; // true
 
 has_template_Template9<Top3>::value; // false
 has_template_Template9<Top4>::value; // true
  
[heading Metafunction re-use]

The macro encodes the name of the inner class template for 
which we are searching, the fact that we are introspecting for 
a class template within an enclosing type, and optionally the 
template parameters for that class template.

Once we create our metafunction for introspecting an inner class 
template by name, we can reuse the metafunction for introspecting 
any enclosing type, having any inner class template, for that name.

However we need to understand that we are restricted in our reuse
of the metafunction by whether we originally use the template type 
parameters form or the specific form. In either case we are always 
introspecting an inner class template which matches that form. 
In the case of the template type parameters form, any inner class 
template for which we are introspecting must have all template type
parameters, as well as the correct name. In the case of the specific
parameters form, any inner class template for which we are 
introspecting must have template parameters which match the specific 
template parameters passed to the macro, as well as the correct name.

[endsect]

[endsect]