vmd_assert.qbk 5.9 KB

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