1[/ 2 (C) Copyright Edward Diener 2011-2015 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:vmd_identifier_subtype Identifier subtypes] 9 10Identifiers are the low-level data types which macro programmers 11use to pass preprocessing data most often. As we have seen VMD 12has a system for registering and detecting identifiers so that 13they can be parsed as part of preprocessor data. This system also 14includes comparing identifiers for equality or inequality using 15BOOST_VMD_EQUAL/BOOST_VMD_NOT_EQUAL and matching identifiers 16using identifier modifiers in BOOST_VMD_IS_IDENTIFIER and 17BOOST_VMD_ELEM. Together these facilities provide a rich set 18of functionality for handling identifiers in macros. 19 20Both numbers and v-types are subtypes of identifiers, and can 21both be individually recognized as data types of their own or 22worked with as identifiers using the identifier facilities 23already mentioned. Numbers, in particular, also have a rich set 24of functionality within the Boost PP library. As subtypes numbers 25and v-types can be used as filter modifiers and can be returned 26as specific types either when invoking BOOST_VMD_GET_TYPE 27or when using return type modifiers. Furthermore VMD recognizes 28their individual v-types, BOOST_VMD_TYPE_NUMBER and 29BOOST_VMD_TYPE_TYPE, as VMD data when parsing sequences. 30 31It is possible for the end-user to define his own identifier subtype. 32This is called a "user-defined subtype". Once a user-define subtype is 33created all the generic type facilities of VMD which subtypes such as 34a number or a v-type possess is automatically available for that 35user-defined subtype. 36 37[heading Defining a subtype] 38 39In order to define a user-defined subtype a number of steps need to be followed. 40These steps will be explained in detail further below: 41 42# Register and pre-detect all identifiers of that subtype. 43# Register and pre-detect a v-type name for that subtype. 44# Subset register all identifiers of the subtype. 45# Subset register the v-type name for the subtype. 46 47When we do the above, it is best to put all the macros in a single 48header file and always include that header file when we work generically 49with our user-defined subtype. 50 51[heading Register and pre-detect all identifiers of that subtype] 52 53Registering and pre-detecting all of the identifiers of that subtype 54is exactly the same as registering and pre-detecting any identifier. 55 56Let's create some identifiers based for use in the mythical "udef" library. 57We will put all our macros in the header file udef_vmd_macros.hpp. 58 59We will need distinct names for the identifiers in our library, so we will 60append UDEF_ to our identifier names to make them unique. Our udef library 61deals in geometrical shapes so we will create a user-defined subtype which 62consists of identifiers for the various shapes our udef library can 63manipulate in their macros. So our identifier registrations and pre-detections 64placed in our header file will be: 65 66 #define BOOST_VMD_REGISTER_UDEF_CIRCLE (UDEF_CIRCLE) 67 #define BOOST_VMD_REGISTER_UDEF_SQUARE (UDEF_SQUARE) 68 #define BOOST_VMD_REGISTER_UDEF_TRIANGLE (UDEF_TRIANGLE) 69 #define BOOST_VMD_REGISTER_UDEF_HEXAGON (UDEF_HEXAGON) 70 71 #define BOOST_VMD_DETECT_UDEF_CIRCLE_UDEF_CIRCLE 72 #define BOOST_VMD_DETECT_UDEF_SQUARE_UDEF_SQUARE 73 #define BOOST_VMD_DETECT_UDEF_TRIANGLE_UDEF_TRIANGLE 74 #define BOOST_VMD_DETECT_UDEF_HEXAGON_UDEF_HEXAGON 75 76[heading Register and pre-detect a v-type name for that subtype] 77 78We need to create a unique v-type name for our user-defined subtype. 79The name does not have to begin with BOOST_VMD_TYPE_ but it should be 80unique. Since BOOST_VMD_TYPE_ is the common beginning of all v-types 81we will use it for consistency but will append to it UDEF_SHAPES to 82give it a uniqueness which should not be duplicated: 83 84 #define BOOST_VMD_REGISTER_BOOST_VMD_TYPE_UDEF_SHAPES (BOOST_VMD_TYPE_UDEF_SHAPES) 85 86 #define BOOST_VMD_DETECT_BOOST_VMD_TYPE_UDEF_SHAPES_BOOST_VMD_TYPE_UDEF_SHAPES 87 88[heading Subtype register all identifiers of the subtype] 89 90The macro to register an identifier subset starts with BOOST_VMD_SUBTYPE_REGISTER_ 91and you append to it each identifier in the subset. This is very much like the 92way you use the BOOST_VMD_REGISTER_ macro. The difference is that unlike the 93BOOST_VMD_REGISTER_ macro, which expands to a tuple whose single element is the 94identifier, the BOOST_VMD_SUBTYPE_REGISTER_ expands to a tuple of two elements 95where the first element is the subtype v-type and the second element is the identifier. 96 97For our udef user-defined subtype this would be: 98 99 #define BOOST_VMD_SUBTYPE_REGISTER_UDEF_CIRCLE (BOOST_VMD_TYPE_UDEF_SHAPES,UDEF_CIRCLE) 100 #define BOOST_VMD_SUBTYPE_REGISTER_UDEF_SQUARE (BOOST_VMD_TYPE_UDEF_SHAPES,UDEF_SQUARE) 101 #define BOOST_VMD_SUBTYPE_REGISTER_UDEF_TRIANGLE (BOOST_VMD_TYPE_UDEF_SHAPES,UDEF_TRIANGLE) 102 #define BOOST_VMD_SUBTYPE_REGISTER_UDEF_HEXAGON (BOOST_VMD_TYPE_UDEF_SHAPES,UDEF_HEXAGON) 103 104[heading Subtype register the v-type name for the subtype] 105 106Doing a subset register of the actual udef v-type is fairly easy once we understand 107how to register an identifier subset. The only particular thing to realize is 108that the type of any v-type is the v-type BOOST_VMD_TYPE_TYPE. So our subset 109register of our new v-type BOOST_VMD_TYPE_UDEF_SHAPES is: 110 111 #define BOOST_VMD_SUBTYPE_REGISTER_BOOST_VMD_TYPE_UDEF_SHAPES (BOOST_VMD_TYPE_TYPE,BOOST_VMD_TYPE_UDEF_SHAPES) 112 113[heading Using our identifier subset] 114 115Once we have added all of the above object-like macros for defining our user-defined 116subtype to the udef_vmd_macros.hpp header file we have a new data type which we can 117use generically just like we can use numbers or v-types generically. It is important 118to include the header udef_vmd_macros.hpp in some translation unit whenever we need 119the VMD functionality for our new data type. So in our examples we will assume that 120an '#include udef_vmd_macros.hpp' precedes each example. 121 122 #include <boost/vmd/get_type.hpp> 123 124 #define A_SEQUENCE UDEF_SQUARE 125 #define A_SEQUENCE2 217 126 #define A_SEQUENCE3 BOOST_VMD_TYPE_UDEF_SHAPES 127 #define A_SEQUENCE4 BOOST_VMD_TYPE_NUMBER 128 129 BOOST_VMD_GET_TYPE(A_SEQUENCE) will return 'BOOST_VMD_TYPE_UDEF_SHAPES' 130 BOOST_VMD_GET_TYPE(A_SEQUENCE2) will return 'BOOST_VMD_TYPE_NUMBER' 131 BOOST_VMD_GET_TYPE(A_SEQUENCE3) will return 'BOOST_VMD_TYPE_TYPE' 132 BOOST_VMD_GET_TYPE(A_SEQUENCE4) will return 'BOOST_VMD_TYPE_TYPE' 133 134Here we see that when we use our BOOST_VMD_GET_TYPE macro on a single-element 135sequence which is one of our user-defined subtype values we correctly get back 136our user-defined subtype's v-type, just like we do when we ask for the type of a number. Also 137when we use our BOOST_VMD_GET_TYPE macro on our user-defined subtype's v-type itself we correctly 138get back the type of all v-types, which is BOOST_VMD_TYPE_TYPE, just like we do 139when we ask for the type of the v-type of a number. 140 141 #include <boost/vmd/elem.hpp> 142 143 #define A_SEQUENCE5 (1,2) UDEF_TRIANGLE 144 145 BOOST_VMD_ELEM(1,A_SEQUENCE5,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_UDEF_SHAPES,UDEF_TRIANGLE)' 146 BOOST_VMD_ELEM(0,A_SEQUENCE5,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_TUPLE,(1,2))' 147 148Here we see that we can use the return type modifier to get back both the type 149and the value in a two-element tuple for our user-defined subtype just as we so 150for any other type. 151 152 #include <boost/vmd/equal.hpp> 153 154 #define A_SEQUENCE6 UDEF_CIRCLE 155 #define A_SEQUENCE7 168 156 157 BOOST_VMD_EQUAL(A_SEQUENCE6,UDEF_CIRCLE,BOOST_VMD_TYPE_UDEF_SHAPES) will return '1' 158 BOOST_VMD_EQUAL(A_SEQUENCE6,UDEF_CIRCLE,BOOST_VMD_TYPE_LIST) will return '0' 159 BOOST_VMD_EQUAL(A_SEQUENCE7,168,BOOST_VMD_TYPE_NUMBER) will return '1' 160 BOOST_VMD_EQUAL(A_SEQUENCE7,168,BOOST_VMD_TYPE_SEQ) will return '0' 161 162Here we can see that we can use the filter modifier with our user-defined subtype's v-type 163just as we can do with any other v-type, such as the number v-type. 164 165In all respects once we define our subtype and provide those definitions in 166a header file, our user-defined subtype acts like any other v-type in our system. 167Since VMD functionality is largely based on being able to recognize the type of 168data in macro input being able to define another 'type', as an identifier subtype, 169which VMD understands has value for the macro programmer. 170 171[heading Uniqueness of identifier subtype values and v-type] 172 173When we define a new identifier subtype we need to be careful that 174the values of that subtype and its actual v-type are unique identifiers 175within any translation unit. This is the main difference between just 176defining identifiers and defining an identifier subtype. 177 178Recall that when we just register and pre-detect identifiers we will have 179no problems if the same identifiers already have been registered and pre-detected 180within the same translation unit. This is because we are just redefining the 181exact same macro if this is the case. 182 183But with identifier subtypes, when we use the BOOST_VMD_SUBTYPE_REGISTER_ macro 184to associate our subtype's v-type with our subtype identifiers, we will have 185problems if someone else has also defined an identifier subtype using the same 186identifiers as we use since we will be redefining the same object-like macro name 187with a different expansion. Even if someone else has registered/pre-detected an 188identifier we are using for out subtype without defining a subtype based on that 189identifier we will be causing a problem defining our subtype because VMD macros which 190generically return the type of a sequence or sequence element will return our 191subtype as the type rather than just BOOST_VMD_TYPE_IDENTIFIER which some programmer 192might expect. 193 194The gist of this is that if we define a user-defined subtype its identifiers need 195to be unique within a given translation unit, and yet unique names make it harder 196for an end-user to use macros more naturally. In our given example with the mythical 197udef library we used identifiers such as 'UDEF_CIRCLE' etc. instead of the more natural 198sounding CIRCLE. So with user-defined identifier subtypes we have a tradeoff; we need 199unique identifier names both for our subtype identifiers and the v-type for our 200subtype identifiers so as not to conflict with others who might be using identifier 201subtypes, but those unique names might make using macros less "natural" On the other 202hand, just registering/pre-detecting identifiers has no such problem. This is an 203issue of which any user, looking to create his own data type using VMD by defining 204user-defined subtypes, should be aware. 205 206[endsect] 207