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