1[/ 2 (C) Copyright Edward Diener 2011-2015 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 http://www.boost.org/LICENSE_1_0.txt). 6] 7 8[section:vmd_assert Asserting and data types] 9 10The VMD macros for identifying data types work best when the macro logic can take different 11paths depending on the type of data being passed for a macro parameter. But occasionally 12the preprocessor metaprogrammer wants to simply verify that the macro parameter data is of 13the correct data type, else a preprocessing error should be generated to notify the programmer 14invoking the macro that the data passed is the incorrect type. 15 16[heading Using BOOST_VMD_ASSERT] 17 18The Boost PP library has a macro which produces a preprocessing error when the condition 19passed to it is 0. This macro is called BOOST_PP_ASSERT. The macro produces a preprocessor 20error by forcing a call to an internal macro with the wrong number of arguments. According 21to the C++ standard this should always cause an immediate preprocessing error for conforming 22compilers. 23 24Unfortunately VC++ will only produce a warning when the wrong number of arguments are passed 25to a macro. Therefore the BOOST_PP_ASSERT macro does not produce a preprocessing error using 26VC++. Amazingly enough there appears to be no other way in which VC++ can be forced to 27issue a preprocessing error by invoking a macro ( if you find one please tell me about it ). 28However one can create invalid C++ as the output from a macro invocation which causes VC++ 29to produce a compiler error when the VC++ compiler later encounters the construct. 30 31This is what the macro BOOST_VMD_ASSERT does. It takes the same conditional argument as 32BOOST_PP_ASSERT and it calls BOOST_PP_ASSERT when not used with VC++, otherwise if the 33condition is 0 it generates a compiler error by generating invalid C++ when used with VC++. 34The compiler error is generated by producing invalid C++ whose form is: 35 36 typedef char BOOST_VMD_ASSERT_ERROR[-1]; 37 38By passing a second optional argument, whose form is a preprocessing identifier, 39to BOOST_VMD_ASSERT you can generate the invalid C++ for VC++, if the first 40argument is 0, of the form: 41 42 typedef char optional_argument[-1]; 43 44instead. This may give a little more clarity, if desired, to the C++ error generated. 45 46If the first conditional argument is not 0, BOOST_VMD_ASSERT produces no output. 47 48[heading BOOST_VMD_ASSERT Usage] 49 50To use the BOOST_VMD_ASSERT macro either include the general header: 51 52 #include <boost/vmd/vmd.hpp> 53 54or include the specific header: 55 56 #include <boost/vmd/assert.hpp> 57 58[heading Assertions for data types ] 59 60The data types have their own assertion macros. These are largely just shortcuts for 61passing the result of the identifying macros to BOOST_VMD_ASSERT. These assertion 62macros are: 63 64* emptiness, BOOST_VMD_ASSERT_IS_EMPTY 65* identifier, BOOST_VMD_ASSERT_IS_IDENTIFIER 66* number, BOOST_VMD_ASSERT_IS_NUMBER 67* array, BOOST_VMD_ASSERT_IS_ARRAY 68* list, BOOST_VMD_ASSERT_IS_LIST 69* seq, BOOST_VMD_ASSERT_IS_SEQ 70* tuple, BOOST_VMD_ASSERT_IS_TUPLE 71* type, BOOST_VMD_ASSERT_IS_TYPE 72 73Each of these macros take as parameters the exact same argument as their 74corresponding identifying macros. But instead of returning non-zero or 0, each of these 75macros produce a compiler error if the type of the input is not correct. 76 77Each of these macros only check for its assertion when the macro BOOST_VMD_ASSERT_DATA 78is set to 1. By default BOOST_VMD_ASSERT_DATA is only set to 1 in compiler debug mode. 79The programmer can manually set BOOST_VMD_ASSERT_DATA to 1 prior to using one 80the data types assert macros if he wishes. 81 82[heading BOOST_VMD_ASSERT_... Usage] 83 84To use the individual BOOST_VMD_ASSERT_... macros either include the general header: 85 86 #include <boost/vmd/vmd.hpp> 87 88or include the specific header: 89 90 #include <boost/vmd/assert_is_empty.hpp> // BOOST_VMD_ASSERT_IS_EMPTY 91 #include <boost/vmd/assert_is_identifier.hpp> // BOOST_VMD_ASSERT_IS_IDENTIFIER 92 #include <boost/vmd/assert_is_number.hpp> // BOOST_VMD_ASSERT_IS_NUMBER 93 #include <boost/vmd/assert_is_array.hpp> // BOOST_VMD_ASSERT_IS_ARRAY 94 #include <boost/vmd/assert_is_list.hpp> // BOOST_VMD_ASSERT_IS_LIST 95 #include <boost/vmd/assert_is_seq.hpp> // BOOST_VMD_ASSERT_IS_SEQ 96 #include <boost/vmd/assert_is_tuple.hpp> // BOOST_VMD_ASSERT_IS_TUPLE 97 #include <boost/vmd/assert_is_type.hpp> // BOOST_VMD_ASSERT_IS_TYPE 98 99[heading Assertions and VC++ ] 100 101The VC++ compiler has a quirk when dealing with BOOST_VMD_ASSERT and the 102data type assert macros. If you invoke one of the assert macros within another 103macro which would normally generate output preprocessor tokens, it is necessary when using 104VC++ to concatenate the result of the assert macro to whatever other preprocessor data 105is being generated, even if the assert macro does not generate an error. 106 107As a simple example let us suppose we have a macro expecting a tuple and generating 1 108if the tuple has more than 2 elements, otherwise it generates 0. Ordinarily we could 109write: 110 111 #include <boost/preprocessor/comparison/greater.hpp> 112 #include <boost/preprocessor/control/iif.hpp> 113 #include <boost/preprocessor/tuple/size.hpp> 114 #include <boost/vmd/assert_is_tuple.hpp> 115 116 #define AMACRO(atuple) \ 117 BOOST_VMD_ASSERT_IS_TUPLE(atuple) \ 118 BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0) 119 120but for VC++ we must write 121 122 #include <boost/preprocessor/cat.hpp> 123 #include <boost/preprocessor/comparison/greater.hpp> 124 #include <boost/preprocessor/control/iif.hpp> 125 #include <boost/preprocessor/tuple/size.hpp> 126 #include <boost/vmd/assert_is_tuple.hpp> 127 128 #define AMACRO(atuple) \ 129 BOOST_PP_CAT \ 130 ( \ 131 BOOST_VMD_ASSERT_IS_TUPLE(atuple), \ 132 BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0) \ 133 ) 134 135VC++ does not work correctly in the first instance, erroneously getting confused as far as 136compiler output is concerned. But by using BOOST_PP_CAT in the second condition VC++ will 137work correctly with VMD assertions. 138 139[endsect] 140