2 [/ Copyright (C) 2009-2012 Lorenzo Caminiti ]
3 [/ Distributed under the Boost Software License, Version 1.0 ]
4 [/ (see accompanying file LICENSE_1_0.txt or a copy at ]
5 [/ http://www.boost.org/LICENSE_1_0.txt) ]
6 [/ Home at http://www.boost.org/libs/utility/identity_type ]
8 [library Boost.Utility/IdentityType
11 [copyright 2009-2012 Lorenzo Caminiti]
12 [purpose wraps types with round parenthesis]
14 Distributed under the Boost Software License, Version 1.0
15 (see accompanying file LICENSE_1_0.txt or a copy at
16 [@http://www.boost.org/LICENSE_1_0.txt])
18 [authors [Caminiti <email>lorcaminiti@gmail.com</email>, Lorenzo]]
22 This library allows to wrap types within round parenthesis so they can always be passed as macro parameters.
24 [import ../test/var_error.cpp]
25 [import ../test/var.cpp]
26 [import ../test/template.cpp]
27 [import ../test/abstract.cpp]
28 [import ../test/paren.cpp]
32 Consider the following macro which declares a variable named `var`[^['n]] with the specified [^['type]] (see also [@../../test/var_error.cpp =var_error.cpp=]):
36 The first macro invocation works correctly declaring a variable named `var1` of type `int`.
37 However, the second macro invocation fails generating a preprocessor error similar to the following:
40 error: macro "VAR" passed 3 arguments, but takes just 2
43 That is because the `std::map` type passed as the first macro parameter contains a comma `,` not wrapped by round parenthesis `()`.
44 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:
50 Note that, differently from the compiler, the preprocessor only recognizes round parenthesis `()`.
51 Angular `<>` and squared `[]` parenthesis are not recognized by the preprocessor when parsing macro parameters.
57 In some cases, it might be possible to workaround this issue by avoiding to pass the type expression to the macro all together.
58 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=]):
62 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=]).
66 The [macroref BOOST_IDENTITY_TYPE] macro expands to an expression that evaluates (at compile-time) to the specified type.
67 The specified type is never split into multiple macro parameters because it is always wrapped by a set of extra round parenthesis `()`.
68 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((...))`.
70 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]).
72 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).
74 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.
75 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.
81 This macro must be prefixed by `typename` when used within templates.
82 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=]):
87 However, note that the template parameter `char` must be manually specified when invoking the function as in `f<char>(a)`.
88 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.
90 This is because the implementation of [macroref BOOST_IDENTITY_TYPE] wraps the specified type within a meta-function.
92 (This limitation does not apply to class templates because class template parameters must always be explicitly specified.)
93 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:
100 [section Abstract Types]
102 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.
103 This can be avoided by manipulating the type adding and removing a reference to it.
105 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`]).
106 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).
107 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=]):
113 [section Annex: Usage]
115 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).
116 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=]):
120 However, note that the caller will /always/ have to specify the extra parenthesis even when the macro parameters contain no comma:
124 In some cases, using [macroref BOOST_IDENTITY_TYPE] in the implementation of the user-defined macro might provide the best syntax for the caller.
125 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]:
127 BOOST_MPL_ASSERT(( // Natural syntax.
130 , boost::is_reference<T>
134 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].
135 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:
137 int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax.
139 } BOOST_LOCAL_FUNCTION_NAME(add)
141 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)`).
145 [section Annex: Implementation]
147 The implementation of this library macro is equivalent to the following:
149 There is absolutely no guarantee that the macro is actually implemented using the code listed in this documentation.
150 The listed code is for explanatory purposes only.
153 #include <boost/type_traits/function_traits.hpp>
155 #define BOOST_IDENTITY_TYPE(parenthesized_type) \
156 boost::function_traits<void parenthesized_type>::arg1_type
158 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.
159 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>)`.
160 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).
164 [xinclude reference.xml]