identity_type.qbk 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. [/ Copyright (C) 2009-2012 Lorenzo Caminiti ]
  2. [/ Distributed under the Boost Software License, Version 1.0 ]
  3. [/ (see accompanying file LICENSE_1_0.txt or a copy at ]
  4. [/ http://www.boost.org/LICENSE_1_0.txt) ]
  5. [/ Home at http://www.boost.org/libs/utility/identity_type ]
  6. [library Boost.Utility/IdentityType
  7. [quickbook 1.5]
  8. [version 1.0.0]
  9. [copyright 2009-2012 Lorenzo Caminiti]
  10. [purpose wraps types with round parenthesis]
  11. [license
  12. Distributed under the Boost Software License, Version 1.0
  13. (see accompanying file LICENSE_1_0.txt or a copy at
  14. [@http://www.boost.org/LICENSE_1_0.txt])
  15. ]
  16. [authors [Caminiti <email>lorcaminiti@gmail.com</email>, Lorenzo]]
  17. [category Utilities]
  18. ]
  19. This library allows to wrap types within round parenthesis so they can always be passed as macro parameters.
  20. [import ../test/var_error.cpp]
  21. [import ../test/var.cpp]
  22. [import ../test/template.cpp]
  23. [import ../test/abstract.cpp]
  24. [import ../test/paren.cpp]
  25. [section Motivation]
  26. Consider the following macro which declares a variable named `var`[^['n]] with the specified [^['type]] (see also [@../../test/var_error.cpp =var_error.cpp=]):
  27. [var_error]
  28. The first macro invocation works correctly declaring a variable named `var1` of type `int`.
  29. However, the second macro invocation fails generating a preprocessor error similar to the following:
  30. [pre
  31. error: macro "VAR" passed 3 arguments, but takes just 2
  32. ]
  33. That is because the `std::map` type passed as the first macro parameter contains a comma `,` not wrapped by round parenthesis `()`.
  34. The preprocessor interprets that unwrapped comma as a separation between macro parameters concluding that a total of three (and not two) parameters are passed to the macro in the following order:
  35. # `std::map<int`
  36. # `char>`
  37. # `2`
  38. Note that, differently from the compiler, the preprocessor only recognizes round parenthesis `()`.
  39. Angular `<>` and squared `[]` parenthesis are not recognized by the preprocessor when parsing macro parameters.
  40. [endsect]
  41. [section Solution]
  42. In some cases, it might be possible to workaround this issue by avoiding to pass the type expression to the macro all together.
  43. For example, in the case above a `typedef` could have been used to specify the type expression with the commas outside the macro (see also [@../../test/var.cpp =var.cpp=]):
  44. [var_typedef]
  45. When this is neither possible nor desired (e.g., see the function template `f` in the section below), this library header [headerref boost/utility/identity_type.hpp] defines a macro [macroref BOOST_IDENTITY_TYPE] which can be used to workaround the issue while keeping the type expression as one of the macro parameters (see also [@../../test/var.cpp =var.cpp=]).
  46. [var_ok]
  47. The [macroref BOOST_IDENTITY_TYPE] macro expands to an expression that evaluates (at compile-time) to the specified type.
  48. The specified type is never split into multiple macro parameters because it is always wrapped by a set of extra round parenthesis `()`.
  49. In fact, a total of two sets of round parenthesis must be used: The parenthesis to invoke the macro `BOOST_IDENTITY_TYPE(...)` plus the inner parenthesis to wrap the type passed to the macro `BOOST_IDENTITY_TYPE((...))`.
  50. This macro works on any [@http://www.open-std.org/JTC1/SC22/WG21/docs/standards C++03] compiler (and it does not use [@http://en.wikipedia.org/wiki/Variadic_macro variadic macros]).
  51. [footnote
  52. Using variadic macros, it would be possible to require a single set of extra parenthesis `BOOST_IDENTITY_TYPE(`[^['type]]`)` instead of two `BOOST_IDENTITY_TYPE((`[^['type]]`))` but variadic macros are not part of C++03 (even if nowadays they are supported by most modern compilers and they are also part of C++11).
  53. ]
  54. The authors originally developed and tested this library using GNU Compiler Collection (GCC) C++ 4.5.3 (with and without C++11 features enabled `-std=c++0x`) on Cygwin and Miscrosoft Visual C++ (MSVC) 8.0 on Windows 7.
  55. See the library [@http://www.boost.org/development/tests/release/developer/utility-identity_type.html regressions test results] for more information on supported compilers and platforms.
  56. [endsect]
  57. [section Templates]
  58. This macro must be prefixed by `typename` when used within templates.
  59. For example, let's program a macro that declares a function parameter named `arg`[^['n]] with the specified [^['type]] (see also [@../../test/template.cpp =template.cpp=]):
  60. [template_f_decl]
  61. [template_f_call]
  62. However, note that the template parameter `char` must be manually specified when invoking the function as in `f<char>(a)`.
  63. In fact, when the [macroref BOOST_IDENTITY_TYPE] macro is used to wrap a function template parameter, the template parameter can no longer be automatically deduced by the compiler form the function call as `f(a)` would have done.
  64. [footnote
  65. This is because the implementation of [macroref BOOST_IDENTITY_TYPE] wraps the specified type within a meta-function.
  66. ]
  67. (This limitation does not apply to class templates because class template parameters must always be explicitly specified.)
  68. In other words, without using the [macroref BOOST_IDENTITY_TYPE] macro, C++ would normally be able to automatically deduce the function template parameter as shown below:
  69. [template_g_decl]
  70. [template_g_call]
  71. [endsect]
  72. [section Abstract Types]
  73. On some compilers (e.g., GCC), using this macro on abstract types (i.e., classes with one or more pure virtual functions) generates a compiler error.
  74. This can be avoided by manipulating the type adding and removing a reference to it.
  75. Let's program a macro that performs a static assertion on a [@http://en.wikipedia.org/wiki/Template_metaprogramming Template Meta-Programming] (TMP) meta-function (similarly to Boost.MPL [@http://www.boost.org/doc/libs/1_36_0/libs/mpl/doc/refmanual/assert.html `BOOST_MPL_ASSERT`]).
  76. The [macroref BOOST_IDENTITY_TYPE] macro can be used to pass a meta-function with multiple template parameters to the assert macro (so to handle the commas separating the template parameters).
  77. In this case, if the meta-function is an abstract type, it needs to be manipulated adding and removing a reference to it (see also [@../../test/abstract.cpp =abstract.cpp=]):
  78. [abstract]
  79. [endsect]
  80. [section Annex: Usage]
  81. The [macroref BOOST_IDENTITY_TYPE] macro can be used either when calling a user-defined macro (as shown by the examples so far), or internally when implementing a user-defined macro (as shown below).
  82. When [macroref BOOST_IDENTITY_TYPE] is used in the implementation of the user-defined macro, the caller of the user macro will have to specify the extra parenthesis (see also [@../../test/paren.cpp =paren.cpp=]):
  83. [paren]
  84. However, note that the caller will /always/ have to specify the extra parenthesis even when the macro parameters contain no comma:
  85. [paren_always]
  86. In some cases, using [macroref BOOST_IDENTITY_TYPE] in the implementation of the user-defined macro might provide the best syntax for the caller.
  87. For example, this is the case for `BOOST_MPL_ASSERT` because the majority of template meta-programming expressions contain unwrapped commas so it is less confusing for the user to always specify the extra parenthesis `((...))` instead of using [macroref BOOST_IDENTITY_TYPE]:
  88. BOOST_MPL_ASSERT(( // Natural syntax.
  89. boost::mpl::and_<
  90. boost::is_const<T>
  91. , boost::is_reference<T>
  92. >
  93. ));
  94. However, in other situations it might be preferable to not require the extra parenthesis in the common cases and handle commas as special cases using [macroref BOOST_IDENTITY_TYPE].
  95. For example, this is the case for [@http://www.boost.org/libs/local_function `BOOST_LOCAL_FUNCTION`] for which always requiring the extra parenthesis `((...))` around the types would lead to an unnatural syntax for the local function signature:
  96. int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax.
  97. return x + y;
  98. } BOOST_LOCAL_FUNCTION_NAME(add)
  99. Instead requiring the user to specify [macroref BOOST_IDENTITY_TYPE] only when needed allows for the more natural syntax `BOOST_LOCAL_FUNCTION(int& x, int& y)` in the common cases when the parameter types contain no comma (while still allowing to specify parameter types with commas as special cases using `BOOST_LOCAL_FUNCTION(BOOST_IDENTITY_TYPE((std::map<int, char>))& x, int& y)`).
  100. [endsect]
  101. [section Annex: Implementation]
  102. The implementation of this library macro is equivalent to the following:
  103. [footnote
  104. There is absolutely no guarantee that the macro is actually implemented using the code listed in this documentation.
  105. The listed code is for explanatory purposes only.
  106. ]
  107. #include <boost/type_traits/function_traits.hpp>
  108. #define BOOST_IDENTITY_TYPE(parenthesized_type) \
  109. boost::function_traits<void parenthesized_type>::arg1_type
  110. Essentially, the type is wrapped between round parenthesis `(std::map<int, char>)` so it can be passed as a single macro parameter even if it contains commas.
  111. Then the parenthesized type is transformed into the type of a function returning `void` and with the specified type as the type of the first and only argument `void (std::map<int, char>)`.
  112. Finally, the type of the first argument `arg1_type` is extracted at compile-time using the `function_traits` meta-function therefore obtaining the original type from the parenthesized type (effectively stripping the extra parenthesis from around the specified type).
  113. [endsect]
  114. [xinclude reference.xml]