123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- [/
- (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_assert Asserting and data types]
- The VMD macros for identifying data types work best when the macro logic can take different
- paths depending on the type of data being passed for a macro parameter. But occasionally
- the preprocessor metaprogrammer wants to simply verify that the macro parameter data is of
- the correct data type, else a preprocessing error should be generated to notify the programmer
- invoking the macro that the data passed is the incorrect type.
- [heading Using BOOST_VMD_ASSERT]
- The Boost PP library has a macro which produces a preprocessing error when the condition
- passed to it is 0. This macro is called BOOST_PP_ASSERT. The macro produces a preprocessor
- error by forcing a call to an internal macro with the wrong number of arguments. According
- to the C++ standard this should always cause an immediate preprocessing error for conforming
- compilers.
- Unfortunately VC++ will only produce a warning when the wrong number of arguments are passed
- to a macro. Therefore the BOOST_PP_ASSERT macro does not produce a preprocessing error using
- VC++. Amazingly enough there appears to be no other way in which VC++ can be forced to
- issue a preprocessing error by invoking a macro ( if you find one please tell me about it ).
- However one can create invalid C++ as the output from a macro invocation which causes VC++
- to produce a compiler error when the VC++ compiler later encounters the construct.
- This is what the macro BOOST_VMD_ASSERT does. It takes the same conditional argument as
- BOOST_PP_ASSERT and it calls BOOST_PP_ASSERT when not used with VC++, otherwise if the
- condition is 0 it generates a compiler error by generating invalid C++ when used with VC++.
- The compiler error is generated by producing invalid C++ whose form is:
- typedef char BOOST_VMD_ASSERT_ERROR[-1];
-
- By passing a second optional argument, whose form is a preprocessing identifier,
- to BOOST_VMD_ASSERT you can generate the invalid C++ for VC++, if the first
- argument is 0, of the form:
- typedef char optional_argument[-1];
-
- instead. This may give a little more clarity, if desired, to the C++ error generated.
- If the first conditional argument is not 0, BOOST_VMD_ASSERT produces no output.
- [heading BOOST_VMD_ASSERT Usage]
- To use the BOOST_VMD_ASSERT macro either include the general header:
- #include <boost/vmd/vmd.hpp>
-
- or include the specific header:
- #include <boost/vmd/assert.hpp>
-
- [heading Assertions for data types ]
- The data types have their own assertion macros. These are largely just shortcuts for
- passing the result of the identifying macros to BOOST_VMD_ASSERT. These assertion
- macros are:
- * emptiness, BOOST_VMD_ASSERT_IS_EMPTY
- * identifier, BOOST_VMD_ASSERT_IS_IDENTIFIER
- * number, BOOST_VMD_ASSERT_IS_NUMBER
- * array, BOOST_VMD_ASSERT_IS_ARRAY
- * list, BOOST_VMD_ASSERT_IS_LIST
- * seq, BOOST_VMD_ASSERT_IS_SEQ
- * tuple, BOOST_VMD_ASSERT_IS_TUPLE
- * type, BOOST_VMD_ASSERT_IS_TYPE
- Each of these macros take as parameters the exact same argument as their
- corresponding identifying macros. But instead of returning non-zero or 0, each of these
- macros produce a compiler error if the type of the input is not correct.
- Each of these macros only check for its assertion when the macro BOOST_VMD_ASSERT_DATA
- is set to 1. By default BOOST_VMD_ASSERT_DATA is only set to 1 in compiler debug mode.
- The programmer can manually set BOOST_VMD_ASSERT_DATA to 1 prior to using one
- the data types assert macros if he wishes.
- [heading BOOST_VMD_ASSERT_... Usage]
- To use the individual BOOST_VMD_ASSERT_... macros either include the general header:
- #include <boost/vmd/vmd.hpp>
-
- or include the specific header:
- #include <boost/vmd/assert_is_empty.hpp> // BOOST_VMD_ASSERT_IS_EMPTY
- #include <boost/vmd/assert_is_identifier.hpp> // BOOST_VMD_ASSERT_IS_IDENTIFIER
- #include <boost/vmd/assert_is_number.hpp> // BOOST_VMD_ASSERT_IS_NUMBER
- #include <boost/vmd/assert_is_array.hpp> // BOOST_VMD_ASSERT_IS_ARRAY
- #include <boost/vmd/assert_is_list.hpp> // BOOST_VMD_ASSERT_IS_LIST
- #include <boost/vmd/assert_is_seq.hpp> // BOOST_VMD_ASSERT_IS_SEQ
- #include <boost/vmd/assert_is_tuple.hpp> // BOOST_VMD_ASSERT_IS_TUPLE
- #include <boost/vmd/assert_is_type.hpp> // BOOST_VMD_ASSERT_IS_TYPE
-
- [heading Assertions and VC++ ]
- The VC++ compiler has a quirk when dealing with BOOST_VMD_ASSERT and the
- data type assert macros. If you invoke one of the assert macros within another
- macro which would normally generate output preprocessor tokens, it is necessary when using
- VC++ to concatenate the result of the assert macro to whatever other preprocessor data
- is being generated, even if the assert macro does not generate an error.
- As a simple example let us suppose we have a macro expecting a tuple and generating 1
- if the tuple has more than 2 elements, otherwise it generates 0. Ordinarily we could
- write:
- #include <boost/preprocessor/comparison/greater.hpp>
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/tuple/size.hpp>
- #include <boost/vmd/assert_is_tuple.hpp>
-
- #define AMACRO(atuple) \
- BOOST_VMD_ASSERT_IS_TUPLE(atuple) \
- BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0)
-
- but for VC++ we must write
- #include <boost/preprocessor/cat.hpp>
- #include <boost/preprocessor/comparison/greater.hpp>
- #include <boost/preprocessor/control/iif.hpp>
- #include <boost/preprocessor/tuple/size.hpp>
- #include <boost/vmd/assert_is_tuple.hpp>
-
- #define AMACRO(atuple) \
- BOOST_PP_CAT \
- ( \
- BOOST_VMD_ASSERT_IS_TUPLE(atuple), \
- BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0) \
- )
-
- VC++ does not work correctly in the first instance, erroneously getting confused as far as
- compiler output is concerned. But by using BOOST_PP_CAT in the second condition VC++ will
- work correctly with VMD assertions.
-
- [endsect]
|