[/ 
  (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_modifiers_filter Filtering modifiers]

Filtering modifiers are optional modifiers which work
with some generic macros to specify a type of
data to apply to the macro's functionality. The filtering
modifier itself is an optional parameter specified as a 
v-type. Any v-type, specified as an optional parameter,
may be used as a filtering modifier.

[heading Usage with equality macros]

The equality macros, BOOST_VMD_EQUAL and BOOST_VMD_NOT_EQUAL, tests
generically whether each of its two required inputs are equal or
not equal to each other.

Each of these macro takes a single optional parameter, a filtering
modifier, to narrow the focus of its equality testing to a particular
v-type.

For the macro BOOST_VMD_EQUAL this optional parameter when specified means 
that equality is not only that the two required input parameters are equal 
but also that they are of the type or of a subtype of the third optional 
parameter. A number and a v-type are subtypes of identifiers 
while a non-empty list and an array are subtypes of tuples.

Conversely BOOST_VMD_NOT_EQUAL, with the optional third v-type parameter,
returns 1 if either the first two parameters are not equal or if the type of
the first two parameters is not the type or a subtype of the third parameter.
Otherwise it returns 0. It is implemented as the complement of BOOST_VMD_EQUAL
so that whenever BOOST_VMD_EQUAL returns 1, BOOST_VMD_NOT_EQUAL returns 0
and vice versa.

Here is an example of using BOOST_VMD_EQUAL with a filtering modifier.
BOOST_VMD_NOT_EQUAL is just the complement of the results in our example
for each result, and would be redundant to be specified each time below.

 #include <boost/vmd/equal.hpp>
 
 #define BOOST_VMD_REGISTER_AN_ID1 (AN_ID1)
 #define BOOST_VMD_REGISTER_AN_ID2 (AN_ID2)
 
 #define BOOST_VMD_DETECT_AN_ID1_AN_ID1
 #define BOOST_VMD_DETECT_AN_ID2_AN_ID2
 
 #define AN_IDENTIFIER1 AN_ID1
 #define AN_IDENTIFIER2 AN_ID2
 #define AN_IDENTIFIER3 AN_ID1 // same as AN_IDENTIFIER1 = AN_ID1
 
 #define A_NUMBER1 33
 #define A_NUMBER2 145
 #define A_NUMBER3 33 // same as A_NUMBER1 = 33
 
 #define A_TUPLE1 (AN_IDENTIFIER1,A_NUMBER1)
 #define A_TUPLE2 (AN_IDENTIFIER1,A_NUMBER2)
 #define A_TUPLE3 (AN_IDENTIFIER3,A_NUMBER3) // same as A_TUPLE1 = (AN_ID1,33)
 
 #define A_LIST1 (A_NUMBER1,(A_NUMBER3,BOOST_PP_NIL))
 #define A_LIST2 (A_NUMBER1,(A_NUMBER2,BOOST_PP_NIL))
 #define A_LIST3 (A_NUMBER1,(A_NUMBER3,BOOST_PP_NIL))
 #define A_LIST4 BOOST_PP_NIL // empty list
 #define A_LIST5 BOOST_PP_NIL // empty list

 BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER2,BOOST_VMD_TYPE_IDENTIFIER) will return 0
 BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER3,BOOST_VMD_TYPE_IDENTIFIER) will return 1
 BOOST_VMD_EQUAL(AN_IDENTIFIER1,AN_IDENTIFIER3,BOOST_VMD_TYPE_TYPE) will return 0 because the type does not match
 
 BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER2,BOOST_VMD_TYPE_NUMBER) will return 0
 BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER3,BOOST_VMD_TYPE_NUMBER) will return 1
 BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER3,BOOST_VMD_TYPE_IDENTIFIER) will return 1 because a number is an identifier
 BOOST_VMD_EQUAL(A_NUMBER1,A_NUMBER3,BOOST_VMD_TYPE_EMPTY) will return 0 because the type does not match
 
 BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE2,BOOST_VMD_TYPE_TUPLE) will return 0
 BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE3,BOOST_VMD_TYPE_TUPLE) will return 1
 BOOST_VMD_EQUAL(A_TUPLE1,A_TUPLE3,BOOST_VMD_TYPE_ARRAY) will return 0 because the type does not match
 
 BOOST_VMD_EQUAL(A_LIST1,A_LIST2,BOOST_VMD_TYPE_LIST) will return 0
 BOOST_VMD_EQUAL(A_LIST1,A_LIST3,BOOST_VMD_TYPE_LIST) will return 1
 BOOST_VMD_EQUAL(A_LIST1,A_LIST3,BOOST_VMD_TYPE_IDENTIFIER) will return 0 because the type does not match
 BOOST_VMD_EQUAL(A_LIST1,A_LIST3,BOOST_VMD_TYPE_TUPLE) will return 1 because a non-empty list is also a tuple
 BOOST_VMD_EQUAL(A_LIST4,A_LIST5,BOOST_VMD_TYPE_LIST) will return 1
 BOOST_VMD_EQUAL(A_LIST4,A_LIST5,BOOST_VMD_TYPE_IDENTIFIER) will return 1 because an empty list is also an identifier
 BOOST_VMD_EQUAL(A_LIST4,A_LIST5,BOOST_VMD_TYPE_TUPLE) will return 0 because an empty list is not a tuple

[heading Usage with BOOST_VMD_ELEM]

As with the equality macros BOOST_VMD_ELEM allows one to perform
filtering for the result. An optional parameter of a v-type can be 
used so that BOOST_VMD_ELEM returns its result only if the sequence 
element is of the v-type specified, else it fails to find the
element in the same way that an element number which is outside
the bounds of the sequence fails.

 #include <boost/vmd/elem.hpp>
 
 #define BOOST_VMD_REGISTER_ANAME (ANAME) // an identifier must always be registered to be found by VMD
 #define A_SEQUENCE (1,2,3) 46 (list_data1,(list_data2,BOOST_PP_NIL)) BOOST_VMD_TYPE_SEQ ANAME
 
 BOOST_VMD_ELEM(0,A_SEQUENCE) will return (1,2,3)
 BOOST_VMD_ELEM(0,A_SEQUENCE,BOOST_VMD_TYPE_TUPLE) will return (1,2,3)
 BOOST_VMD_ELEM(0,A_SEQUENCE,BOOST_VMD_TYPE_SEQ) will return emptiness
 
 BOOST_VMD_ELEM(1,A_SEQUENCE) will return 46
 BOOST_VMD_ELEM(1,A_SEQUENCE,BOOST_VMD_TYPE_NUMBER) will return 46
 BOOST_VMD_ELEM(1,A_SEQUENCE,BOOST_VMD_TYPE_IDENTIFIER) will return 46 since a number is also an identifier
 BOOST_VMD_ELEM(1,A_SEQUENCE,BOOST_VMD_TYPE_LIST) will return emptiness
 
 BOOST_VMD_ELEM(2,A_SEQUENCE) will return (list_data1,(list_data2,BOOST_PP_NIL))
 BOOST_VMD_ELEM(2,A_SEQUENCE,BOOST_VMD_TYPE_LIST) will return (list_data1,(list_data2,BOOST_PP_NIL))
 BOOST_VMD_ELEM(2,A_SEQUENCE,BOOST_VMD_TYPE_TUPLE) will return (list_data1,(list_data2,BOOST_PP_NIL)) since a list is also a tuple
 BOOST_VMD_ELEM(2,A_SEQUENCE,BOOST_VMD_TYPE_TYPE) will return emptiness
 
 BOOST_VMD_ELEM(3,A_SEQUENCE) will return BOOST_VMD_TYPE_SEQ
 BOOST_VMD_ELEM(3,A_SEQUENCE,BOOST_VMD_TYPE_TYPE) will return BOOST_VMD_TYPE_SEQ
 BOOST_VMD_ELEM(3,A_SEQUENCE,BOOST_VMD_TYPE_IDENTIFIER) will return BOOST_VMD_TYPE_SEQ since a type is also an identifier
 BOOST_VMD_ELEM(3,A_SEQUENCE,BOOST_VMD_TYPE_TUPLE) will return emptiness
 
 BOOST_VMD_ELEM(4,A_SEQUENCE) will return ANAME
 BOOST_VMD_ELEM(4,A_SEQUENCE,BOOST_VMD_TYPE_IDENTIFIER) will return ANAME
 BOOST_VMD_ELEM(4,A_SEQUENCE,BOOST_VMD_TYPE_NUMBER) will return emptiness
 
 BOOST_VMD_ELEM(0,BOOST_PP_NIL) will return BOOST_PP_NIL
 BOOST_VMD_ELEM(0,BOOST_PP_NIL,BOOST_VMD_TYPE_LIST) will return BOOST_PP_NIL since it is an empty list
 BOOST_VMD_ELEM(0,BOOST_PP_NIL,BOOST_VMD_TYPE_IDENTIFIER) will return BOOST_PP_NIL since it a registered identifier
 BOOST_VMD_ELEM(0,BOOST_PP_NIL,BOOST_VMD_TYPE_TUPLE) will return emptiness
 
If you specify more than one v-type as a filtering modifier to BOOST_VMD_ELEM
the last v-type becomes the filter.

Filtering with BOOST_VMD_ELEM denotes the type of the data expected when
the particular element is found. Because filtering represents the type of
the data requested, filtering modifiers and return type modifiers are
mutually exclusive and any filtering modifier means that return
type modifiers specified are ignored.

[endsect]