315 lines
13 KiB
Plaintext
315 lines
13 KiB
Plaintext
[/
|
|
(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]
|