140 lines
5.9 KiB
Plaintext
140 lines
5.9 KiB
Plaintext
[/
|
|
(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]
|