| [/ |
| (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_functionality General Functionality] |
| |
| The elements of a type about which a template metaprogrammer might be interested in finding |
| out at compile time are: |
| |
| * Does it have a nested type with a particular name ? |
| * Does it have a nested type with a particular name which fulfills some other possibility for that nested type. |
| * Does it have a particular user-defined nested type (struct/class, union, or enumaeration) with a particular name ? |
| * Does it have a particular user-defined nested type with a particular name which fulfills some other possibility for that nested type. |
| * Does it have a nested class template with a particular name ? |
| * Does it have a nested class template with a particular name and a particular signature ? |
| * Does it have a nested member function template with a particular name and a particular instantiated signature ? |
| * Does it have a nested static function template with a particular name and a particular instantiated signature ? |
| * Does it have a member function with a particular name and a particular signature ? |
| * Does it have member data with a particular name and of a particular type ? |
| * Does it have a static member function with a particular name and a particular signature ? |
| * Does it have static member data with a particular name and of a particular type ? |
| * Does it have either member data or static member data with a particular name and of a particular type ? |
| * Does it have either a member function or static member function with a particular name and of a particular type ? |
| |
| These are some of the compile-time questions which the TTI library answers. It |
| does this by creating metafunctions, which can be used at compile-time, using |
| C++ macros. Each of the metafunctions created returns a compile time constant |
| bool value which answers one of the above questions at compile time. When the |
| particular element above exists the value is 'true', or more precisely |
| boost::mpl::true_, while if the element does not exist the value is 'false', |
| or more precisely boost::mpl::false_. In either case the type of this value |
| is boost::mpl::bool_. |
| |
| This constant bool value, in the terminology of the Boost MPL library, is called an 'integral |
| constant wrapper' and the metafunction generated is called a 'numerical metafunction'. The |
| results from calling the metafunction can be passed to other metafunctions for type selection, |
| the most popular of these being the boolean-valued operators in the Boost MPL library. |
| |
| All of the questions above attempt to find an answer about an inner element with |
| a particular name. In order to do this using template metaprogramming, macros are used |
| so that the name of the inner element can be passed to the macro. The macro will then |
| generate an appropriate metafunction, which the template metaprogrammer can then use to |
| introspect the information that is needed. The name itself of the inner element is always passed |
| to the macro as a macro parameter, but other macro parameters may also be needed in some cases. |
| |
| All of the macros start with the prefix `BOOST_TTI_`, create their metafunctions as class |
| templates in whatever scope the user invokes the macro, and come in two forms: |
| |
| # In the simplest macro form, which I call the simple macro form, the 'name' of the inner element |
| is used directly to generate the name of the metafunction as well as serving as the 'name' |
| to introspect. In generating the name of the metafunction from the macro name, the |
| `BOOST_TTI_` prefix is removed, the rest of the macro name is changed to lower case, and an |
| underscore ( '_' ) followed by the 'name' is appended. As an example, for the macro |
| `BOOST_TTI_HAS_TYPE(MyType)` the name of the metafunction is `has_type_MyType` and it will |
| look for an inner type called 'MyType'. |
| # In a more complicated macro form, which I call the complex macro form, the macro starts with |
| `BOOST_TTI_TRAIT_` and a 'trait' name is passed as the first parameter, with the 'name' of the inner |
| element as the second parameter. The 'trait' name serves solely to completely name the metafunction in |
| whatever scope the macro is invoked. As an example, for the macro |
| `BOOST_TTI_TRAIT_HAS_TYPE(MyTrait,MyType)` the name of |
| the metafunction is `MyTrait` and it will look for an inner type called `MyType`. |
| |
| Every macro metafunction has a simple macro form and a corresponding complex macro form. |
| Once either of these two macro forms are used for a particular type of inner element, the |
| corresponding macro metafunction works exactly the same way and has the exact same functionality. |
| |
| In the succeeding documentation all macro metafunctions will be referred by their simple form |
| name, but remember that the complex form can always be used instead. The complex form is useful |
| whenever using the simple form could create a duplicate name in the same name space, thereby |
| violating the C++ one definition rule. |
| |
| [heading Macro Metafunction Name Generation] |
| |
| For the simple macro form, even though it is fairly easy to remember the algorithm by which |
| the generated metafunction is named, TTI also provides, for each macro metafunction, |
| a corresponding 'naming' macro which the end-user can use and whose sole purpose |
| is to expand to the metafunction name. The naming macro for each macro metafunction has the form: |
| 'corresponding-macro'_GEN(name). |
| |
| As an example, BOOST_TTI_HAS_TYPE(MyType) creates a metafunction |
| which looks for a nested type called 'MyType' within some enclosing type. The name of the metafunction |
| generated, given our rule above is 'has_type_MyType'. A corresponding macro called |
| BOOST_TTI_HAS_TYPE_GEN, invoked as BOOST_TTI_HAS_TYPE_GEN(MyType) in our example, expands to the |
| same 'has_type_MyType' name. These name generating macros, for each of the metafunction generating macros, |
| are purely a convenience for end-users who find using them easier than remembering the name-generating |
| rule given above. |
| |
| [section:tti_functionality_nm_gen Macro metafunction name generation considerations] |
| |
| Because having a double underscore ( __ ) in a name is reserved by the C++ implementation, |
| creating C++ identifiers with double underscores should be avoided by the end-user. When using |
| a TTI macro to generate a metafunction using the simple macro form, TTI appends a single |
| underscore to the macro name preceding the name of the element that is being introspected. |
| The reason for doing this is because Boost discourages as non-portable C++ identifiers with mixed |
| case letters and the underscore then becomes the normal way to separate parts of an identifier |
| name so that it looks understandable. Because of this decision to use the underscore to generate |
| the metafunction name from the macro name, any inner element starting with an underscore will cause |
| the identifier for the metafunction name being generated to contain a double underscore. |
| |
| A rule to avoid this problem is: |
| |
| * When the name of the inner element to be introspected begins with an underscore, use |
| the complex macro form, where the name of the metafunction is specifically given. |
| |
| Furthermore because TTI often generates not only a metafunction for the end-user to use but some |
| supporting detail metafunctions whose identifier, for reasons of programming clarity, is the same |
| as the metafunction with further letters appended to it separated by an underscore, another rule is: |
| |
| * When using the complex macro form, which fully gives the name of the generated |
| macro metafunction, that name should not end with an underscore. |
| |
| Following these two simple rules will avoid names with double underscores being |
| generated by TTI. |
| |
| [heading Reusing the named metafunction] |
| |
| When the end-user uses the TTI macros to generate a metafunction for introspecting an inner |
| element of a particular type, that metafunction can be re-used with any combination of valid |
| template parameters which involve the same type of inner element of a particular name. |
| |
| As one example of this let's consider two different user-defined types called |
| 'AType' and 'BType', for each of which we want to determine whether an inner type called |
| 'InnerType' exists. For both these types we need only generate a single macro metafunction in |
| the current scope by using: |
| |
| BOOST_TTI_HAS_TYPE(InnerType) |
| |
| We now have a metafunction, which is a C++ class template, in the current scope whose C++ identifier |
| is 'has_type_InnerType'. We can use this same metafunction to introspect the existence of the nested type |
| 'InnerType' in either 'AType' or 'BType' at compile time. Although the syntax for doing this has no yet |
| been explained, I will give it here so that you can see how 'has_type_InnerType' is reused: |
| |
| # 'has_type_InnerType<AType>::value' is a compile time constant telling us whether 'InnerType' is a |
| type which is nested within 'AType'. |
| |
| # 'has_type_InnerType<BType>::value' is a compile time constant telling us whether 'InnerType' is a |
| type which is nested within 'BType'. |
| |
| As another example of metafunction reuse let's consider a single user-defined type, called 'CType', |
| for which we want to determine if it has either of two overloaded member functions with the same name |
| of 'AMemberFunction' but with the different function signatures of 'int (int)' and 'double (long)'. |
| For both these member functions we need only generate a single macro metafunction in the current scope |
| by using: |
| |
| BOOST_TTI_HAS_MEMBER_FUNCTION(AMemberFunction) |
| |
| We now have a metafunction, which is a C++ class template, in the current scope whose C++ identifier |
| is 'has_member_function_AMemberFunction'. We can use this same metafunction to introspect the |
| existence of the member function 'AMemberFunction' with either the function signature of |
| 'int (int)' or 'double (long)' in 'CType' at compile time. Although the syntax for doing this has no yet |
| been explained, I will give it here so that you can see how 'has_type_InnerType' is reused: |
| |
| # 'has_member_function_AMemberFunction<CType,int,boost::mpl::vector<int> >::value' is a |
| compile time constant telling us whether 'AMemberFunction' is a member function of type 'CType' |
| whose function signature is 'int (int)'. |
| |
| # 'has_member_function_AMemberFunction<CType,double,boost::mpl::vector<long> >::value' is a |
| compile time constant telling us whether 'AMemberFunction' is a member function of type 'CType' |
| whose function signature is 'double (long)'. |
| |
| These are just two examples of the ways a particular macro metafunction can be reused. The two |
| 'constants' when generating a macro metafunction are the 'name' and 'type of inner element'. Once |
| the macro metafunction for a particular name and inner element type has been generated, it can be reused |
| for introspecting the inner element(s) of any enclosing type which correspond to that name and |
| inner element type. |
| |
| [heading Avoiding ODR violations] |
| |
| The TTI macro metafunctions are generating directly in the enclosing scope in which the |
| corresponding macro is invoked. This can be any C++ scope in which a class template can |
| be specified. Within this enclosing scope the name of the metafunction |
| being generated must be unique or else a C++ ODR ( One Definition Rule ) violation will occur. |
| This is extremely important to remember, especially when the enclosing scope can occur in |
| more than one translation unit, which is the case for namespaces and the global scope. |
| |
| Because of ODR, and the way that the simple macro form metafunction name is directly dependent |
| on the inner element and name of the element being introspected, it is the responsibility of the |
| programmer, using the TTI macros to generate metafunctions, to avoid ODR within a module |
| ( application or library ). There are a few general methods for doing this: |
| |
| # Create unique namespace names in which to generate the macro metafunctions and/or generate |
| the macro metafunctions in C++ scopes which can not extend across translation units. The most |
| obvious example of this latter is within C++ classes. |
| |
| # Use the complex macro form to specifically name the metafunction generated in order to |
| provide a unique name. |
| |
| # Avoid using the TTI macros in the global scope. |
| |
| For anyone using TTI in a library which others will eventually use, it is important |
| to generate metafunction names which are unique to that library. |
| |
| TTI also reserves not only the name generated by the macro metafunction for its use |
| but also any C++ identifier sequence which begins with that name. In other words |
| if the metafunction being generated by TTI is named 'MyMetafunction' using the complex |
| macro form, do not create any C++ construct with an identifier starting with 'MyMetaFunction', |
| such as 'MyMetaFunction_Enumeration' or 'MyMetaFunctionHelper' in the same scope. |
| All names starting with the metafunction name in the current scope should be considered |
| out of bounds for the programmer using TTI. |
| |
| [endsect] |
| |
| [endsect] |