[/ 
  (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 variadic 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
 
However if our data consists of more than one consecutive tuple of a single
element the data is always 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

[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 not 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 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]
