vmd_whyhow.qbk 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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_whyhow Why and how to use]
  8. The VMD library provides the ability to create a macro which takes
  9. different types of parameters and can therefore generate different output
  10. depending on the parameter types as well as their values.
  11. This is equivalent to the way that overloaded
  12. functions provide the ability for a singularly named function
  13. to provide different functionality depending on the parameter
  14. types.
  15. In the case of macros, where more than one macro of the same
  16. name but different macro expansion is not allowed, a single macro name
  17. can create different expansions.
  18. As a simple example:
  19. #include <boost/vmd/is_seq.hpp>
  20. #include <boost/vmd/is_tuple.hpp>
  21. #define AMACRO(param) \
  22. BOOST_PP_IIF \
  23. ( \
  24. BOOST_VMD_IS_SEQ(param), \
  25. Seq, \
  26. BOOST_PP_IIF \
  27. ( \
  28. BOOST_VMD_IS_TUPLE(param), \
  29. Tuple, \
  30. Unknown \
  31. ) \
  32. )
  33. If the param passed is a seq the output of
  34. the macro is 'Seq'. If the param passed is
  35. a tuple the output of the macro is 'Tuple'.
  36. Otherwise the output of the macro is 'Unknown'.
  37. Obviously much more complicated cases can be created
  38. in which the types and values of various parameters
  39. are parsed in order to produce variable macro output
  40. depending on the input. Using variadic macros,
  41. macros with variable numbers and types of arguments
  42. give the macro programmer even greater freedom to
  43. design macros with flexibility.
  44. Another feature of the VMD library is the ability to parse
  45. identifiers. A system of registering identifiers which VMD
  46. can recognize has been created. Once an identifier is registered
  47. VMD can recognize it as part of macro input as an identifier and
  48. return the identifier. Furthermore VMD can compare identifiers
  49. for equality or inequality once an identifier has been pre-detected
  50. using VMD's system for pre-detecting identifiers.
  51. As another simple example:
  52. #include <boost/vmd/is_identifier.hpp>
  53. #define BOOST_VMD_REGISTER_NAME (NAME)
  54. #define BOOST_VMD_REGISTER_ADDRESS (ADDRESS)
  55. #define AMACRO1(param) \
  56. BOOST_PP_IIF \
  57. ( \
  58. BOOST_VMD_IS_IDENTIFIER(param), \
  59. AMACRO1_IDENTIFIER, \
  60. AMACRO1_NO_IDENTIFIER \
  61. ) \
  62. (param)
  63. #define AMACRO1_IDENTIFIER(param) AMACRO1_ ## param
  64. #define AMACRO1_NO_IDENTIFIER(param) Parameter is not an identifier
  65. #define AMACRO1_NAME Identifier is a NAME
  66. #define AMACRO1_ADDRESS Identifier is an ADDRESS
  67. Here we use VMD's identifier registration system to determine and
  68. handle a particular identifier we may be expecting as a macro parameter.
  69. If the input to 'AMACRO1' is 'NAME' the output is 'Identifier is a NAME'.
  70. If the input to 'AMACRO1' is 'ADDRESS' the output is 'Identifier is an ADDRESS'.
  71. Otherwise the output is 'Parameter is not an identifier'.
  72. Identifier pre-detection makes things clearer, allowing us to
  73. detect within VMD whether macro input matches a particular identifier.
  74. Using the same setup as our previous example, but with identifier pre-detection:
  75. #include <boost/vmd/is_identifier.hpp>
  76. #define BOOST_VMD_REGISTER_NAME (NAME)
  77. #define BOOST_VMD_DETECT_NAME_NAME
  78. #define BOOST_VMD_REGISTER_ADDRESS (ADDRESS)
  79. #define BOOST_VMD_DETECT_ADDRESS_ADDRESS
  80. #define AMACRO2(param) \
  81. BOOST_PP_IIF \
  82. ( \
  83. BOOST_VMD_IS_IDENTIFIER(param,NAME), \
  84. AMACRO2_NAME, \
  85. BOOST_PP_IIF \
  86. ( \
  87. BOOST_VMD_IS_IDENTIFIER(param,ADDRESS), \
  88. AMACRO2_ADDRESS, \
  89. AMACRO2_NO_IDENTIFIER \
  90. ) \
  91. ) \
  92. (param)
  93. #define AMACRO2_NO_IDENTIFIER(param) Parameter is not a NAME or ADDRESS identifier
  94. #define AMACRO2_NAME(param) Identifier is a NAME
  95. #define AMACRO2_ADDRESS(param) Identifier is an ADDRESS
  96. If the input to 'AMACRO2' is 'NAME' the output is 'Identifier is a NAME'.
  97. If the input to 'AMACRO2' is 'ADDRESS' the output is 'Identifier is an ADDRESS'.
  98. Otherwise the output is 'Parameter is not a NAME or ADDRESS identifier'.
  99. The VMD library also has 2 different subtypes of identifiers which can always be
  100. recognized. The first are numbers, equivalent to the number in Boost PP, numeric
  101. values with a range of 0-256. The second are v-types, which are identifiers starting
  102. with BOOST_VMD_TYPE_ followed by a name for the type of data. As an example, the v-type
  103. of a Boost PP tuple is BOOST_VMD_TYPE_TUPLE and the v-type of a v-type itself is
  104. BOOST_VMD_TYPE_TYPE. All data types have their own v-type identifier; types are
  105. recognized by the VMD macros and may be passed as input data just like any other of
  106. the types of data VMD recognizes.
  107. The VMD identifier system even has a way, to be explained later, for the end-user to
  108. create his own subtype identifiers.
  109. Another reason to use VMD is that VMD understands 'sequences' of the VMD data types. You
  110. can have a sequence of data types and VMD can convert the sequence to any of the Boost
  111. PP data types, or access any individual data type in a sequence.
  112. #include <boost/vmd/elem.hpp>
  113. #include <boost/vmd/to_tuple.hpp>
  114. #define BOOST_VMD_REGISTER_NAME (NAME)
  115. #define ASEQUENCE (1,2) NAME 147 BOOST_VMD_TYPE_NUMBER (a)(b)
  116. BOOST_VMD_TO_TUPLE(ASEQUENCE)
  117. BOOST_VMD_ELEM(2,ASEQUENCE)
  118. Our first expansion returns the tuple:
  119. ((1,2),NAME,147,BOOST_VMD_TYPE_NUMBER,(a)(b))
  120. Our second expansion returns the sequence element:
  121. 147
  122. Sequences give the macro programmer the ability to accept input
  123. data from the user which may more closely mimic C++ constructs.
  124. Another reason to use VMD is that VMD understands data types.
  125. Besides specifically asking if a particular input is a particular
  126. data type, you can use the macro BOOST_VMD_GET_TYPE to retrieve
  127. the type of any VMD data.
  128. #include <boost/vmd/get_type.hpp>
  129. BOOST_VMD_GET_TYPE((1,2)) // expands to BOOST_VMD_TYPE_TUPLE
  130. BOOST_VMD_GET_TYPE(235) // expands to BOOST_VMD_TYPE_NUMBER
  131. etc.
  132. There is still much more of VMD functionality but hopefully this brief
  133. introduction of what VMD can do will interest you so that you will read on
  134. to understand VMD's functionality for the macro programmer.
  135. [endsect]