123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- [/
- (C) Copyright Edward Diener 2011-2015
- 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:vmd_pp_data_types VMD and Boost PP data types]
- VMD is able to determine whether or not preprocessing input
- is a given Boost PP data type. The VMD macros to do this are:
- * BOOST_VMD_IS_ARRAY for an array
- * BOOST_VMD_IS_LIST for a list
- * BOOST_VMD_IS_SEQ for a seq
- * BOOST_VMD_IS_TUPLE for a tuple
- Each of these macros take a single parameter as input and
- return 1 if the parameter is the appropriate data type and
- 0 if it is not.
- [heading Syntax anomalies]
- Both an array and a non-empty list are also a tuple. So if
- one has:
- #define ANARRAY (3,(a,b,c))
- #define ALIST (a,(b,(c,BOOST_PP_NIL)))
- #define ATUPLE (a,b,c)
- #define ASEQ (a)(b)(c)
-
- then
-
- #include <boost/vmd/is_tuple.hpp>
-
- BOOST_VMD_IS_TUPLE(ANARRAY) returns 1
- BOOST_VMD_IS_TUPLE(ALIST) returns 1
- BOOST_VMD_IS_TUPLE(ATUPLE) returns 1
- BOOST_VMD_IS_TUPLE(ASEQ) returns 0
-
- A list whose first element is the number 2 and whose second
- element is not the end-of-list marker BOOST_PP_NIL is also
- an array. So if one has:
- #define ALIST (2,(3,BOOST_PP_NIL))
- #define ALIST2 (2,(3,(4,BOOST_PP_NIL)))
- #define ALIST3 (2,BOOST_PP_NIL)
-
- #include <boost/vmd/is_array.hpp>
- #include <boost/vmd/is_list.hpp>
-
- BOOST_VMD_IS_LIST(ALIST) returns 1
- BOOST_VMD_IS_LIST(ALIST2) returns 1
- BOOST_VMD_IS_LIST(ALIST3) returns 1
- BOOST_VMD_IS_ARRAY(ALIST) returns 1
- BOOST_VMD_IS_ARRAY(ALIST2) returns 1
- BOOST_VMD_IS_ARRAY(ALIST3) returns 0
-
- A single element tuple is also a one element seq. So if one has:
- #define ASE_TUPLE (a)
-
- then
- #include <boost/vmd/is_seq.hpp>
- #include <boost/vmd/is_tuple.hpp>
-
- BOOST_VMD_IS_TUPLE(ASE_TUPLE) returns 1
- BOOST_VMD_IS_SEQ(ASE_TUPLE) returns 1
-
- [heading Problem when testing an array]
- The form of an array is a two element tuple, where the first
- element is a number and the second element is a tuple. The number
- specifies the size of the tuple. Since when using variadic macros
- it is never necessary to specify the size of a tuple, an array is
- largely obsolete. However VMD still supports it.
- The problem when testing for an array is that if the first element
- does not obey the constraint on testing for a number, you will get
- UB.
- #include <boost/vmd/is_array.hpp>
- #include <boost/vmd/is_tuple.hpp>
-
- #define A_TUPLE (&anything,(1,2))
-
- BOOST_VMD_IS_ARRAY(A_TUPLE) will give UB due to the constraint
- BOOST_VMD_IS_TUPLE(A_TUPLE) will return 1
-
- When VMD attempts to parse for an array, as it does when the BOOST_VMD_IS_ARRAY
- is used, if first looks to see if the syntax represents a tuple with two elements.
- Next it looks to see if the second element itself is a tuple. Finally if it is
- satisfied that the previous checks are valid it tests whether the first element
- is a number or not. It is in this final test, that the first element is a valid
- number, where the UB could occur as explained in the topic 'Numbers'.
- [heading Problem when testing a list]
- The form of a non-empty list is a two element tuple, where the first
- element is the head of the list and can be anything and the
- second element is itself a list or the end-of-list identifier
- BOOST_PP_NIL.
- The problem when testing for a list is that if the second element
- does not obey the constraint on testing for an identifier, since BOOST_PP_NIL
- is an identifier and is tested as such, you will get UB.
- #include <boost/vmd/is_list.hpp>
- #include <boost/vmd/is_tuple.hpp>
-
- #define A_TUPLE (element,&anything)
- BOOST_VMD_IS_LIST(A_TUPLE) will give UB due to the constraint
- BOOST_VMD_IS_TUPLE(A_TUPLE) will return 1
-
- The form of an empty list is the identifier BOOST_PP_NIL. Therefore:
- #include <boost/vmd/is_identifier.hpp>
- #include <boost/vmd/is_list.hpp>
-
- #define A_BAD_EMPTY_LIST &BOOST_PP_NIL
- BOOST_VMD_IS_LIST(A_BAD_EMPTY_LIST) will give UB due to the constraint
- BOOST_VMD_IS_IDENTIFIER(A_BAD_EMPTY_LIST) will give UB due to the constraint
- When VMD attempts to parse for a list, as it does when the BOOST_VMD_IS_LIST
- is used, if first looks to see if the syntax represents a tuple with two elements.
- If it is not a tuple with two elements it will check for the end-of-list.
- If it is a tuple with two elements it looks to see if the second element is a list.
- In both these paths it must always eventually check for the end-of-list notation
- BOOST_PP_NIL, which is an identifier in VMD. It is in this final test, that the
- end-of-list notation exists as a VMD identifier, where the UB
- could occur as explained in the topic 'Identifiers'.
- [heading Distinguishing a seq and a tuple]
- As has previously been mentioned a single element tuple
- is also a one element seq.
- However, as will be discussed later in the documentation, when VMD has to
- determine the type of such data, it always returns it as a tuple ( BOOST_VMD_TYPE_TUPLE ).
- If our data consists of more than one consecutive tuple of a single
- element the data is a seq:
- #include <boost/vmd/is_seq.hpp>
- #include <boost/vmd/is_tuple.hpp>
-
- #define ST_DATA (somedata)(some_other_data)
-
- BOOST_VMD_IS_SEQ(ST_DATA) will return 1
- BOOST_VMD_IS_TUPLE(ST_DATA) will return 0
-
- However if the data consists of a mixture we need to distinguish
- how VMD parses the data. The rule is that VMD always parses a single
- element tuple as a tuple unless it is followed by one or more single
- element tuples, in which case it is a seq.
- #define ST_DATA (somedata)(element1,element2)
-
- VMD parses the above data as 2 consecutive tuples.
- The first tuple is the single element tuple '(somedata)' and the second tuple
- is the multi element tuple '(element1,element2)'.
- #define ST_DATA (element1,element2)(somedata)
-
- VMD parses the above data as 2 consecutive tuples.
- The first tuple is the multi element tuple '(element1,element2)' and the second tuple
- is the single element tuple '(somedata)'.
- #define ST_DATA (somedata)(some_other_data)(element1,element2)
-
- VMD parses the above data as a seq followed by a tuple.
- The seq is '(somedata)(some_other_data)' and the tuple is
- '(element1,element2)'.
- [heading Empty Boost PP data types]
- An array and a list can be empty.
- An empty array has the form '(0,())', and is a perfectly valid array.
- You can test for an empty array using the macro BOOST_VMD_IS_EMPTY_ARRAY.
- #include <boost/vmd/is_array.hpp>
- #include <boost/vmd/is_empty_array.hpp>
-
- #define AN_ARRAY (1,(1))
- #define AN_EMPTY_ARRAY (0,())
-
- BOOST_VMD_IS_ARRAY(AN_ARRAY) will return 1
- BOOST_VMD_IS_ARRAY(AN_EMPTY_ARRAY) will return 1
-
- BOOST_VMD_IS_EMPTY_ARRAY(AN_EMPTY_ARRAY) will return 1
- BOOST_VMD_IS_EMPTY_ARRAY() will return 0
- BOOST_VMD_IS_EMPTY_ARRAY(AN_ARRAY) will return 0
- An empty list has the form 'BOOST_PP_NIL', and is a perfectly valid list.
- You can test for an empty list using the macro BOOST_VMD_IS_EMPTY_LIST.
- #include <boost/vmd/is_empty_list.hpp>
- #include <boost/vmd/is_list.hpp>
-
- #define A_LIST (1,BOOST_PP_NIL)
- #define AN_EMPTY_LIST BOOST_PP_NIL
-
- BOOST_VMD_IS_LIST(A_LIST) will return 1
- BOOST_VMD_IS_LIST(AN_EMPTY_LIST) will return 1
-
- BOOST_VMD_IS_EMPTY_LIST(AN_EMPTY_LIST) will return 1
- BOOST_VMD_IS_EMPTY_LIST() will return 0
- BOOST_VMD_IS_EMPTY_LIST(A_LIST) will return 0
-
- Neither seqs or tuples can be empty when using Boost PP. Because of this if you
- convert from an empty array or list to a seq or tuple using
- Boost PP macros to do so you will get undefined behavior.
- The syntax '()', which is called an empty parenthesis, is neither a
- zero-element seq or a tuple consisting of no elements. Rather it is
- either a one-element seq whose content is emptiness or a single-element
- tuple whose content is emptiness.
- VMD supports the syntax of an empty parenthesis. You can test for it using
- the macro BOOST_VMD_IS_PARENS_EMPTY.
- #include <boost/vmd/is_parens_empty.hpp>
- #include <boost/vmd/is_seq.hpp>
- #include <boost/vmd/is_tuple.hpp>
-
- #define EMPTY_PARENS ()
- #define TUPLE (0)
- #define SEQ (0)(1)
-
- BOOST_VMD_IS_TUPLE(EMPTY_PARENS) will return 1
- BOOST_VMD_IS_SEQ(EMPTY_PARENS) will return 1
-
- BOOST_VMD_IS_PARENS_EMPTY(EMPTY_PARENS) will return 1
- BOOST_VMD_IS_PARENS_EMPTY() will return 0
- BOOST_VMD_IS_PARENS_EMPTY(TUPLE) will return 0
- BOOST_VMD_IS_PARENS_EMPTY(SEQ) will return 0
-
- The VC++8 compiler ( Visual Studio 2005 ), which is the oldest
- VC++ version which VMD supports, has trouble working with the empty
- parenthesis syntax. Therefore if you have to use VC++8 avoid its use,
- otherwise you should be fine using it if you desire.
- [heading Using a tuple instead of an array]
- When using variadic macros, the fact that an array can be empty is its only
- advantage over a tuple. Otherwise using a tuple is always easier since
- the syntax is simpler; you never have to notate the tuple's size.
- Since VMD fully supports passing and returning emptiness you could use a tuple
- instead of an array in all situations and simply pass or return emptiness to
- represent an "empty" tuple, and as an equivalent to an empty array.
- This notion of using emptiness to represent an "empty" tuple can also be extended
- to using emptiness to represent an "empty" seq. However functionality in Boost PP
- will not recognize emptiness as an empty tuple or seq, nor can you work with emptiness
- to represent an empty tuple or empty seq using the Boost PP functionality for a tuple
- or a seq. For a solution to using emptiness to represent an "empty" tuple or an
- "empty" seq VMD has functionality which will be explained when we look at our last
- area of functionality in VMD, useful variadic macros not in Boost PP.
- [heading Usage]
- You can use the general header file:
- #include <boost/vmd/vmd.hpp>
-
- or you can use individual header files for each of these macros.
- The individual header files are:
- #include <boost/vmd/is_array.hpp> // for the BOOST_VMD_IS_ARRAY macro
- #include <boost/vmd/is_list.hpp> // for the BOOST_VMD_IS_LIST macro
- #include <boost/vmd/is_seq.hpp> // for the BOOST_VMD_IS_SEQ macro
- #include <boost/vmd/is_tuple.hpp> // for the BOOST_VMD_IS_TUPLE macro.
-
- #include <boost/vmd/is_empty_array.hpp> // for the BOOST_VMD_IS_EMPTY_ARRAY macro.
- #include <boost/vmd/is_empty_list.hpp> // for the BOOST_VMD_IS_EMPTY_LIST macro.
- #include <boost/vmd/is_parens_empty.hpp> // for the BOOST_VMD_IS_PARENS_EMPTY macro.
- [endsect]
|