| [/ |
| (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] |