| [/ |
| (C) Copyright Edward Diener 2011,2012,2020 |
| 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_type Introspecting an inner type] |
| |
| The TTI macro [macroref BOOST_TTI_HAS_TYPE] introspects |
| a nested type of a class. The type it introspects may be |
| a typedef or, in C++11 on up, a type alias. Or the type may be |
| the user-defined types of a class/struct, enumeration, or union. |
| |
| The BOOST_TTI_HAS_TYPE macro takes a single parameter which is the name of |
| an inner type whose existence the programmer wants to check. The |
| macro generates a metafunction called "has_type_'name_of_inner_type'". |
| |
| The main purpose of the generated metafunction is to check for the existence by |
| name of the inner type. The metafunction can also be used to invoke an MPL lambda |
| expression which is passed the inner type. One of the most common usages of the added |
| functionality is to check whether or not the inner type is an alias for another type, |
| either through a typedef or a type alias. |
| |
| The metafunction is invoked by passing it the enclosing type |
| to introspect. A second type may be passed to the |
| metafunction, an MPL lambda expression taking the inner type |
| and returning a boolean constant. |
| |
| 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 value is true or false depending on whether the inner |
| type exists or not. |
| |
| If a second optional type is passed, this type must be an MPL lambda expression |
| and the expression will be invoked only if the inner type exists. In that case the |
| metafunction returns true or false depending on whether the MPL lambda expression returns |
| true or false. If the inner type does not exist, the MPL lambda expression, even if |
| specified, is never invoked and the metafunction returns false. |
| |
| [heading Generating the metafunction] |
| |
| You generate the metafunction by invoking the macro with the name |
| of an inner type: |
| |
| BOOST_TTI_HAS_TYPE(AType) |
| |
| generates a metafunction called 'has_type_AType' in the current scope. |
| |
| [heading Invoking the metafunction] |
| |
| You invoke the metafunction by instantiating the template with an enclosing |
| type to introspect and, optionally, an MPL lambda expression. |
| A return value called 'value' is a compile time bool constant. |
| |
| has_type_AType<Enclosing_Type>::value |
| has_type_AType<Enclosing_Type,ALambdaExpression>::value |
| |
| [heading Examples] |
| |
| First we generate metafunctions for various inner type names: |
| |
| #include <boost/tti/has_type.hpp> |
| |
| BOOST_TTI_HAS_TYPE(MyTypeDef) |
| BOOST_TTI_HAS_TYPE(AType) |
| BOOST_TTI_HAS_TYPE(ATypeDef) |
| BOOST_TTI_HAS_TYPE(MyType) |
| |
| Next let us create some user-defined types we want to introspect. |
| |
| struct Top |
| { |
| typedef int MyTypeDef; |
| struct AType { }; |
| }; |
| struct Top2 |
| { |
| typedef long ATypeDef; |
| struct MyType { }; |
| }; |
| |
| Finally we invoke our metafunction and return our value. |
| |
| has_type_MyTypeDef<Top>::value; // true |
| has_type_MyTypeDef<Top2>::value; // false |
| |
| has_type_AType<Top>::value; // true |
| has_type_AType<Top2>::value; // false |
| |
| has_type_ATypeDef<Top>::value; // false |
| has_type_ATypeDef<Top2>::value; // true |
| |
| has_type_MyType<Top>::value; // false |
| has_type_MyType<Top2>::value; // true |
| |
| [heading Examples - using lambda expressions] |
| |
| We can further invoke our metafunction with a second type, |
| which is an MPL lambda expression. |
| |
| An MPL lambda expression, an extremely useful technique in |
| template metaprogramming, allows us to pass a metafunction to |
| other metafunctions. The metafunction we pass can be in the form |
| of a placeholder expression or a metafunction class. In our case |
| the metafunction passed to our has_type_'name_of_inner_type' |
| metafunction as an MPL lambda expression must return a boolean constant |
| expression. |
| |
| [heading Example - using an MPL lambda expression with a placeholder expression] |
| |
| We will first illustrate the use of an MPL lambda expression in the |
| form of a placeholder expression being passed as the second template |
| parameter to our has_type_'name_of_inner_type' metafunction. |
| A popular and simple placeholder expression we can use is |
| 'boost::is_same<_1,SomeType>' to check if the inner type found is a |
| particular type. This is particularly useful when the inner type |
| is a typedef for some other type. |
| |
| First we include some more header files and a using declaration |
| for convenience. |
| |
| #include <boost/mpl/placeholders.hpp |
| #include <boost/type_traits/is_same.hpp |
| using namespace boost::mpl::placeholders; |
| |
| Next we invoke our metafunction: |
| |
| has_type_MyTypeDef<Top,boost::is_same<_1,int> >::value; // true |
| has_type_MyTypeDef<Top,boost::is_same<_1,long> >::value; // false |
| |
| has_type_ATypeDef<Top2,boost::is_same<_1,int> >::value; // false |
| has_type_ATypeDef<Top2,boost::is_same<_1,long> >::value; // true |
| |
| [heading Example - using an MPL lambda expression with a metafunction class] |
| |
| We will next illustrate the use of an MPL lambda expression in the |
| form of a metafunction class being passed as the second template |
| parameter to our has_type_'name_of_inner_type' metafunction. |
| |
| A metafunction class is a type which has a nested class template |
| called 'apply'. For our metafunction class example we will check if the |
| inner type is a built-in integer type. First let us write out |
| metafunction class: |
| |
| #include <boost/type_traits/is_integral.hpp> |
| |
| class OurMetafunctionClass |
| { |
| template<class T> struct apply : |
| boost::is_integral<T> |
| { |
| }; |
| }; |
| |
| Now we can invoke our metafunction: |
| |
| has_type_MyTypeDef<Top,OurMetafunctionClass>::value; // true |
| has_type_AType<Top,OurMetafunctionClass>::value; // false |
| |
| has_type_ATypeDef<Top2,OurMetafunctionClass>::value; // true |
| has_type_MyType<Top2,OurMetafunctionClass>::value; // true |
| |
| [heading Metafunction re-use] |
| |
| The macro encodes only the name of the inner type for which |
| we are searching and the fact that we are introspecting for |
| an inner type within an enclosing type. |
| |
| Because of this, once we create our metafunction for |
| introspecting an inner type by name, we can reuse the |
| metafunction for introspecting any enclosing type, having |
| any inner type, for that name. |
| |
| Furthermore since we have only encoded the name of the inner |
| type for which we are introspecting, we can not only introspect |
| for that inner type by name but add different lambda expressions |
| to inspect that inner type for whatever we want to find out about |
| it using the same metafunction. |
| |
| [section:tti_detail_has_specific_type Introspecting a specific user-defined type] |
| |
| Just as you use tti to look for a general type within |
| some enclosing class, struct, or union, you can also |
| look for a specific user-defined inner type. The only difference |
| in this functionality is that the macros and default names |
| for the generated metafunction change for each specific |
| user-defined type. Otherwise the remaining functionality |
| works exactly the way which was described in the previous |
| topics when looking for a general inner type, including the |
| optional use of an MPL lambda expression if the specific inner type |
| is found. |
| |
| The specific inner types, their macros, and default generated |
| metafunction names are given in the following table: |
| |
| [table:tbspinner TTI Specific Inner Types |
| [ |
| [Inner Element] |
| [Simple Macro] |
| [Default Template Name] |
| ] |
| [ |
| [Class or Struct] |
| [[macroref BOOST_TTI_HAS_CLASS](name)] |
| [`has_class_'name'`] |
| ] |
| [ |
| [Enumeration] |
| [[macroref BOOST_TTI_HAS_ENUM](name)] |
| [`has_enum_'name'`] |
| ] |
| [ |
| [Union] |
| [[macroref BOOST_TTI_HAS_UNION](name)] |
| [`has_union_'name'`] |
| ] |
| ] |
| |
| As with the general type you can also use the |
| complex macros form of BOOST_TTI_TRAIT_HAS_CLASS(trait,name), |
| BOOST_TTI_TRAIT_HAS_ENUM(trait,name), and |
| BOOST_TTI_TRAIT_HAS_UNION(trait,name) respectively to |
| directly generate the metafunction name. |
| |
| If you introspect for a specific user-defined type with a |
| given name, and some other type with that given name is found, |
| the metafunction will return the expected value of 'false', but no |
| compiler error will result. |
| |
| In all other respects using these macros/metafunctions for |
| specific inner user-defined types will work in exactly the |
| same way as has been explained for searching for a general |
| inner type. The specific inner type functionality gives the |
| end-user a finer grained introspection facility than |
| looking for a general type within an enclosing user-defined |
| type. |
| |
| [endsect] |
| |
| [endsect] |