]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | (C) Copyright Edward Diener 2011,2012 | |
3 | Distributed under the Boost Software License, Version 1.0. | |
4 | (See accompanying file LICENSE_1_0.txt or copy at | |
5 | http://www.boost.org/LICENSE_1_0.txt). | |
6 | ] | |
7 | ||
8 | [section:tti_functionality General Functionality] | |
9 | ||
10 | The elements of a type about which a template metaprogrammer might be interested in finding | |
11 | out at compile time are: | |
12 | ||
13 | * Does it have a nested type with a particular name ? | |
14 | * Does it have a nested type with a particular name which fulfills some other possibility for that nested type. | |
15 | * Does it have a nested class template with a particular name ? | |
16 | * Does it have a nested class template with a particular name and a particular signature ? | |
17 | * Does it have a member function with a particular name and a particular signature ? | |
18 | * Does it have member data with a particular name and of a particular type ? | |
19 | * Does it have a static member function with a particular name and a particular signature ? | |
20 | * Does it have static member data with a particular name and of a particular type ? | |
21 | * Does it have either member data or static member data with a particular name and of a particular type ? | |
22 | * Does it have either a member function or static member function with a particular name and of a particular type ? | |
23 | ||
24 | These are some of the compile-time questions which the TTI library answers. It | |
25 | does this by creating metafunctions, which can be used at compile-time, using | |
26 | C++ macros. Each of the metafunctions created returns a compile time constant | |
27 | bool value which answers one of the above questions at compile time. When the | |
28 | particular element above exists the value is 'true', or more precisely | |
29 | boost::mpl::true_, while if the element does not exist the value is 'false', | |
30 | or more precisely boost::mpl::false_. In either case the type of this value | |
31 | is boost::mpl::bool_. | |
32 | ||
33 | This constant bool value, in the terminology of the Boost MPL library, is called an 'integral | |
34 | constant wrapper' and the metafunction generated is called a 'numerical metafunction'. The | |
35 | results from calling the metafunction can be passed to other metafunctions for type selection, | |
36 | the most popular of these being the boolean-valued operators in the Boost MPL library. | |
37 | ||
38 | All of the questions above attempt to find an answer about an inner element with | |
39 | a particular name. In order to do this using template metaprogramming, macros are used | |
40 | so that the name of the inner element can be passed to the macro. The macro will then | |
41 | generate an appropriate metafunction, which the template metaprogrammer can then use to | |
42 | introspect the information that is needed. The name itself of the inner element is always passed | |
43 | to the macro as a macro parameter, but other macro parameters may also be needed in some cases. | |
44 | ||
45 | All of the macros start with the prefix `BOOST_TTI_`, create their metafunctions as class | |
46 | templates in whatever scope the user invokes the macro, and come in two forms: | |
47 | ||
48 | # In the simplest macro form, which I call the simple macro form, the 'name' of the inner element | |
49 | is used directly to generate the name of the metafunction as well as serving as the 'name' | |
50 | to introspect. In generating the name of the metafunction from the macro name, the | |
51 | `BOOST_TTI_` prefix is removed, the rest of the macro name is changed to lower case, and an | |
52 | underscore ( '_' ) followed by the 'name' is appended. As an example, for the macro | |
53 | `BOOST_TTI_HAS_TYPE(MyType)` the name of the metafunction is `has_type_MyType` and it will | |
54 | look for an inner type called 'MyType'. | |
55 | # In a more complicated macro form, which I call the complex macro form, the macro starts with | |
56 | `BOOST_TTI_TRAIT_` and a 'trait' name is passed as the first parameter, with the 'name' of the inner | |
57 | element as the second parameter. The 'trait' name serves solely to completely name the metafunction in | |
58 | whatever scope the macro is invoked. As an example, for the macro | |
59 | `BOOST_TTI_TRAIT_HAS_TYPE(MyTrait,MyType)` the name of | |
60 | the metafunction is `MyTrait` and it will look for an inner type called `MyType`. | |
61 | ||
62 | Every macro metafunction has a simple macro form and a corresponding complex macro form. | |
63 | Once either of these two macro forms are used for a particular type of inner element, the | |
64 | corresponding macro metafunction works exactly the same way and has the exact same functionality. | |
65 | ||
66 | In the succeeding documentation all macro metafunctions will be referred by their simple form | |
67 | name, but remember that the complex form can always be used instead. The complex form is useful | |
68 | whenever using the simple form could create a duplicate name in the same name space, thereby | |
69 | violating the C++ one definition rule. | |
70 | ||
71 | [heading Macro Metafunction Name Generation] | |
72 | ||
73 | For the simple macro form, even though it is fairly easy to remember the algorithm by which | |
74 | the generated metafunction is named, TTI also provides, for each macro metafunction, | |
75 | a corresponding 'naming' macro which the end-user can use and whose sole purpose | |
76 | is to expand to the metafunction name. The naming macro for each macro metafunction has the form: | |
77 | 'corresponding-macro'_GEN(name). | |
78 | ||
79 | As an example, BOOST_TTI_HAS_TYPE(MyType) creates a metafunction | |
80 | which looks for a nested type called 'MyType' within some enclosing type. The name of the metafunction | |
81 | generated, given our rule above is 'has_type_MyType'. A corresponding macro called | |
82 | BOOST_TTI_HAS_TYPE_GEN, invoked as BOOST_TTI_HAS_TYPE_GEN(MyType) in our example, expands to the | |
83 | same 'has_type_MyType' name. These name generating macros, for each of the metafunction generating macros, | |
84 | are purely a convenience for end-users who find using them easier than remembering the name-generating | |
85 | rule given above. | |
86 | ||
87 | [section:tti_functionality_nm_gen Macro metafunction name generation considerations] | |
88 | ||
89 | Because having a double underscore ( __ ) in a name is reserved by the C++ implementation, | |
90 | creating C++ identifiers with double underscores should be avoided by the end-user. When using | |
91 | a TTI macro to generate a metafunction using the simple macro form, TTI appends a single | |
92 | underscore to the macro name preceding the name of the element that is being introspected. | |
93 | The reason for doing this is because Boost discourages as non-portable C++ identifiers with mixed | |
94 | case letters and the underscore then becomes the normal way to separate parts of an identifier | |
95 | name so that it looks understandable. Because of this decision to use the underscore to generate | |
96 | the metafunction name from the macro name, any inner element starting with an underscore will cause | |
97 | the identifier for the metafunction name being generated to contain a double underscore. | |
98 | ||
99 | A rule to avoid this problem is: | |
100 | ||
101 | * When the name of the inner element to be introspected begins with an underscore, use | |
102 | the complex macro form, where the name of the metafunction is specifically given. | |
103 | ||
104 | Furthermore because TTI often generates not only a metafunction for the end-user to use but some | |
105 | supporting detail metafunctions whose identifier, for reasons of programming clarity, is the same | |
106 | as the metafunction with further letters appended to it separated by an underscore, another rule is: | |
107 | ||
108 | * When using the complex macro form, which fully gives the name of the generated | |
109 | macro metafunction, that name should not end with an underscore. | |
110 | ||
111 | Following these two simple rules will avoid names with double underscores being | |
112 | generated by TTI. | |
113 | ||
114 | [heading Reusing the named metafunction] | |
115 | ||
116 | When the end-user uses the TTI macros to generate a metafunction for introspecting an inner | |
117 | element of a particular type, that metafunction can be re-used with any combination of valid | |
118 | template parameters which involve the same type of inner element of a particular name. | |
119 | ||
120 | As one example of this let's consider two different types called | |
121 | 'AType' and 'BType', for each of which we want to determine whether an inner type called | |
122 | 'InnerType' exists. For both these types we need only generate a single macro metafunction in | |
123 | the current scope by using: | |
124 | ||
125 | BOOST_TTI_HAS_TYPE(InnerType) | |
126 | ||
127 | We now have a metafunction, which is a C++ class template, in the current scope whose C++ identifier | |
128 | is 'has_type_InnerType'. We can use this same metafunction to introspect the existence of the nested type | |
129 | 'InnerType' in either 'AType' or 'BType' at compile time. Although the syntax for doing this has no yet | |
130 | been explained, I will give it here so that you can see how 'has_type_InnerType' is reused: | |
131 | ||
132 | # 'has_type_InnerType<AType>::value' is a compile time constant telling us whether 'InnerType' is a | |
133 | type which is nested within 'AType'. | |
134 | ||
135 | # 'has_type_InnerType<BType>::value' is a compile time constant telling us whether 'InnerType' is a | |
136 | type which is nested within 'BType'. | |
137 | ||
138 | As another example of metafunction reuse let's consider a single type, called 'CType', for which we want to | |
139 | determine if it has either of two overloaded member functions with the same name of 'AMemberFunction' | |
140 | but with the different function signatures of 'int (int)' and 'double (long)'. For both these | |
141 | member functions we need only generate a single macro metafunction in the current scope by using: | |
142 | ||
143 | BOOST_TTI_HAS_MEMBER_FUNCTION(AMemberFunction) | |
144 | ||
145 | We now have a metafunction, which is a C++ class template, in the current scope whose C++ identifier | |
146 | is 'has_member_function_AMemberFunction'. We can use this same metafunction to introspect the | |
147 | existence of the member function 'AMemberFunction' with either the function signature of | |
148 | 'int (int)' or 'double (long)' in 'CType' at compile time. Although the syntax for doing this has no yet | |
149 | been explained, I will give it here so that you can see how 'has_type_InnerType' is reused: | |
150 | ||
151 | # 'has_member_function_AMemberFunction<CType,int,boost::mpl::vector<int> >::value' is a | |
152 | compile time constant telling us whether 'AMemberFunction' is a member function of type 'CType' | |
153 | whose function signature is 'int (int)'. | |
154 | ||
155 | # 'has_member_function_AMemberFunction<CType,double,boost::mpl::vector<long> >::value' is a | |
156 | compile time constant telling us whether 'AMemberFunction' is a member function of type 'CType' | |
157 | whose function signature is 'double (long)'. | |
158 | ||
159 | These are just two examples of the ways a particular macro metafunction can be reused. The two | |
160 | 'constants' when generating a macro metafunction are the 'name' and 'type of inner element'. Once | |
161 | the macro metafunction for a particular name and inner element type has been generated, it can be reused | |
162 | for introspecting the inner element(s) of any enclosing type which correspond to that name and | |
163 | inner element type. | |
164 | ||
165 | [heading Avoiding ODR violations] | |
166 | ||
167 | The TTI macro metafunctions are generating directly in the enclosing scope in which the | |
168 | corresponding macro is invoked. This can be any C++ scope in which a class template can | |
169 | be specified. Within this enclosing scope the name of the metafunction | |
170 | being generated must be unique or else a C++ ODR ( One Definition Rule ) violation will occur. | |
171 | This is extremely important to remember, especially when the enclosing scope can occur in | |
172 | more than one translation unit, which is the case for namespaces and the global scope. | |
173 | ||
174 | Because of ODR, and the way that the simple macro form metafunction name is directly dependent | |
175 | on the inner element and name of the element being introspected, it is the responsibility of the | |
176 | programmer using the TTI macros to generate metafunctions to avoid ODR within a module | |
177 | ( application or library ). There are a few general methods for doing this: | |
178 | ||
179 | # Create unique namespace names in which to generate the macro metafunctions and/or generate | |
180 | the macro metafunctions in C++ scopes which can not extend across translation units. The most | |
181 | obvious example of this latter is within C++ classes. | |
182 | ||
183 | # Use the complex macro form to specifically name the metafunction generated in order to | |
184 | provide a unique name. | |
185 | ||
186 | # Avoid using the TTI macros in the global scope. | |
187 | ||
188 | For anyone using TTI in a library which others will eventually use, it is important | |
189 | to generate metafunction names which are unique to that library. | |
190 | ||
191 | TTI also reserves not only the name generated by the macro metafunction for its use | |
192 | but also any C++ identifier sequence which begins with that name. In other words | |
193 | if the metafunction being generated by TTI is named 'MyMetafunction' using the complex | |
194 | macro form, do not create any C++ construct with an identifier starting with 'MyMetaFunction', | |
195 | such as 'MyMetaFunction_Enumeration' or 'MyMetaFunctionHelper' in the same scope. | |
196 | All names starting with the metafunction name in the current scope should be considered | |
197 | out of bounds for the programmer using TTI. | |
198 | ||
199 | [endsect] | |
200 | ||
201 | [endsect] |