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