From e763315b55ad2afdfee5712ba1ef417a571a0ec8 Mon Sep 17 00:00:00 2001 From: Daryle Walker Date: Sat, 11 Feb 2012 18:27:02 +0000 Subject: [PATCH 1/8] Updated boost::base_from_member for C++2011. [SVN r76982] --- base_from_member.html | 51 ++++++++++++++++------ include/boost/utility/base_from_member.hpp | 12 ++++- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/base_from_member.html b/base_from_member.html index 21ee6d2..df4add2 100644 --- a/base_from_member.html +++ b/base_from_member.html @@ -129,6 +129,8 @@ particular member type does not need to concern itself with the integer.

Synopsis

+#include <type_traits>  // exposition only
+
 #ifndef BOOST_BASE_FROM_MEMBER_MAX_ARITY
 #define BOOST_BASE_FROM_MEMBER_MAX_ARITY  10
 #endif
@@ -139,6 +141,11 @@ class boost::base_from_member
 protected:
     MemberType  member;
 
+#if C++2011 is in use
+    template< typename ...T >
+    explicit constexpr   base_from_member( T&& ...x )
+     noexcept( std::is_nothrow_constructible<MemberType, T...>::value );
+#else
     base_from_member();
 
     template< typename T1 >
@@ -154,6 +161,7 @@ protected:
      typename T10 >
     base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
      T8 x8, T9 x9, T10 x10 );
+#endif
 };
 
@@ -166,13 +174,27 @@ value of zero if it is omitted. The class template has a protected data member called member that the derived class can use for later base classes (or itself).

-

There is a default constructor and several constructor member -templates. These constructor templates can take as many arguments -(currently up to ten) as possible and pass them to a constructor of -the data member. Since C++ does not allow any way to explicitly state +

If the variadic template arguments and r-value reference features of C++2011 +are present, there will be a single constructor template. It implements +"perfect forwarding" to the best constructor call of +member (if any). The constructor template is marked both +constexpr and explicit. The former will be ignored +if the corresponding inner constructor call (of member) does not +have the marker. The latter binds the other way; always taking effect, even +when the inner constructor call does not have the marker. The constructor +template propagates the noexcept status of the inner constructor +call.

+ +

On earlier-standard compilers, there is a default constructor and several +constructor member templates. These constructor templates can take as many +arguments (currently up to ten) as possible and pass them to a constructor of +the data member.

+ +

Since C++ does not allow any way to explicitly state the template parameters of a templated constructor, make sure that the arguments are already close as possible to the actual type used in -the data member's desired constructor.

+the data member's desired constructor. Explicit conversions may be +necessary.

The BOOST_BASE_FROM_MEMBER_MAX_ARITY macro constant specifies the maximum argument length for the constructor templates. The constant @@ -180,7 +202,7 @@ may be overridden if more (or less) argument configurations are needed. The constant may be read for code that is expandable like the class template and needs to maintain the same maximum size. (Example code would be a class that uses this class template as a base class for a member with a flexible set of -constructors.)

+constructors.) This constant is ignored when C++2011 features are present.

Usage

@@ -323,11 +345,14 @@ constructor argument for pbase0_type is converted from argument for pbase2_type is converted from int to double. The second constructor argument for pbase3_type is a special case of necessary conversion; all -forms of the null-pointer literal in C++ also look like compile-time -integral expressions, so C++ always interprets such code as an integer -when it has overloads that can take either an integer or a pointer. The -last conversion is necessary for the compiler to call a constructor form -with the exact pointer type used in switcher's constructor.

+forms of the null-pointer literal in C++ (except nullptr from +C++2011) also look like compile-time integral expressions, so C++ always +interprets such code as an integer when it has overloads that can take either +an integer or a pointer. The last conversion is necessary for the compiler to +call a constructor form with the exact pointer type used in +switcher's constructor. (If C++2011's nullptr is +used, it still needs a conversion if multiple pointer types can be accepted in +a constructor call but std::nullptr_t cannot.)

Credits

@@ -360,9 +385,9 @@ with the exact pointer type used in switcher's constructor.


-

Revised: 28 August 2004

+

Revised: 11 February 2012

-

Copyright 2001, 2003, 2004 Daryle Walker. Use, modification, and distribution +

Copyright 2001, 2003, 2004, 2012 Daryle Walker. Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

diff --git a/include/boost/utility/base_from_member.hpp b/include/boost/utility/base_from_member.hpp index 04aabb5..8148077 100644 --- a/include/boost/utility/base_from_member.hpp +++ b/include/boost/utility/base_from_member.hpp @@ -1,6 +1,6 @@ // boost utility/base_from_member.hpp header file --------------------------// -// Copyright 2001, 2003, 2004 Daryle Walker. Use, modification, and +// Copyright 2001, 2003, 2004, 2012 Daryle Walker. Use, modification, and // distribution are subject to the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or a copy at // .) @@ -10,6 +10,7 @@ #ifndef BOOST_UTILITY_BASE_FROM_MEMBER_HPP #define BOOST_UTILITY_BASE_FROM_MEMBER_HPP +#include #include #include #include @@ -68,12 +69,21 @@ class base_from_member protected: MemberType member; +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + template + explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) + BOOST_NOEXCEPT_IF( BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType( + static_cast(x)... )) ) // no std::is_nothrow_constructible... + : member( static_cast(x)... ) // ...nor std::forward needed + {} +#else base_from_member() : member() {} BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(BOOST_BASE_FROM_MEMBER_MAX_ARITY), BOOST_PRIVATE_CTR_DEF, _ ) +#endif }; // boost::base_from_member From 9a16aaa2b9ebef80131a6ae5f342320393933cd6 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Wed, 15 Feb 2012 00:41:33 +0000 Subject: [PATCH 2/8] Added LocalFunction and Utility/IdentityType source files. [SVN r77024] --- include/boost/utility/identity_type.hpp | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 include/boost/utility/identity_type.hpp diff --git a/include/boost/utility/identity_type.hpp b/include/boost/utility/identity_type.hpp new file mode 100644 index 0000000..c297c49 --- /dev/null +++ b/include/boost/utility/identity_type.hpp @@ -0,0 +1,45 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/utility/identity_type + +/** @file +Wrap type expressions with round parenthesis so they can be passed to macros +even if they contain commas. +*/ + +#ifndef BOOST_IDENTITY_TYPE_HPP_ +#define BOOST_IDENTITY_TYPE_HPP_ + +#include + +/** +@brief This macro allows to wrap the specified type expression within extra +round parenthesis so the type can be passed as a single macro parameter even if +it contains commas (not already wrapped within round parenthesis). + +@Params +@Param{parenthesized_type, +The type expression to be passed as macro parameter wrapped by a single set +of round parenthesis (...). +This type expression can contain an arbitrary number of commas. +} +@EndParams + +This macro works on any C++03 compiler (it does not require variadic macros). + +This macro must be prefixed by typename when used within templates. +However, the compiler will not be able to automatically determine function template parameters when they are wrapped with this macro (these parameters need to +be explicitly specified when calling the function template). + +On some compilers (like GCC), using this macro on an abstract types requires to +add and remove a reference to the type. +*/ +#define BOOST_IDENTITY_TYPE(parenthesized_type) \ + /* must NOT prefix this with `::` to work with parenthesized syntax */ \ + boost::function_traits< void parenthesized_type >::arg1_type + +#endif // #include guard + From ef0f82f62b8404382ed2ae8a5d338d85f221501a Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Wed, 15 Feb 2012 01:16:00 +0000 Subject: [PATCH 3/8] Added Utility/IdentityType docs, tests, and examples to libs/. [SVN r77029] --- identity_type/doc/Jamfile.v2 | 31 ++++ identity_type/doc/html/index.html | 228 ++++++++++++++++++++++++++++ identity_type/doc/identity_type.qbk | 159 +++++++++++++++++++ identity_type/index.html | 15 ++ identity_type/test/Jamfile.v2 | 14 ++ identity_type/test/template.cpp | 48 ++++++ identity_type/test/tmp_assert.cpp | 51 +++++++ identity_type/test/var.cpp | 26 ++++ identity_type/test/var_err.cpp | 18 +++ 9 files changed, 590 insertions(+) create mode 100644 identity_type/doc/Jamfile.v2 create mode 100644 identity_type/doc/html/index.html create mode 100644 identity_type/doc/identity_type.qbk create mode 100644 identity_type/index.html create mode 100644 identity_type/test/Jamfile.v2 create mode 100644 identity_type/test/template.cpp create mode 100644 identity_type/test/tmp_assert.cpp create mode 100644 identity_type/test/var.cpp create mode 100644 identity_type/test/var_err.cpp diff --git a/identity_type/doc/Jamfile.v2 b/identity_type/doc/Jamfile.v2 new file mode 100644 index 0000000..29ea0a9 --- /dev/null +++ b/identity_type/doc/Jamfile.v2 @@ -0,0 +1,31 @@ + +# Copyright (C) 2009-2012 Lorenzo Caminiti +# Distributed under the Boost Software License, Version 1.0 +# (see accompanying file LICENSE_1_0.txt or a copy at +# http://www.boost.org/LICENSE_1_0.txt) +# Home at http://www.boost.org/libs/utility/identity_type + +import quickbook ; +using boostbook ; + +doxygen reference : ../../../../boost/utility/identity_type.hpp + : "Reference" + PREDEFINED="DOXYGEN" + QUIET=YES + WARN_IF_UNDOCUMENTED=NO + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_CLASSES=YES + ALIASES=" Params=\"Parameters: \" Param{2}=\"\" EndParams=\"
\\1\\2
\" Returns=\"Returns:\" Note=\"Note:\" Warning=\"Warning:\" See=\"See:\" RefSect{1}=\"\\xmlonly\\1\\endxmlonly\" RefSectId{2}=\"\\xmlonly\\2\\endxmlonly\" RefClass{1}=\"\\xmlonly\\1\\endxmlonly\" RefFunc{1}=\"\\xmlonly\\1\\endxmlonly\" RefMacro{1}=\"\\xmlonly\\1\\endxmlonly\" " + ; + +# This target must be called "index" so to generate "index.html" file. +xml index : identity_type.qbk : reference ; + +boostbook doc : index + : html + onehtml + toc.section.depth=0 + html.stylesheet=../../../../../doc/src/boostbook.css + boost.root=../../../../.. + ; + diff --git a/identity_type/doc/html/index.html b/identity_type/doc/html/index.html new file mode 100644 index 0000000..c0dc1ee --- /dev/null +++ b/identity_type/doc/html/index.html @@ -0,0 +1,228 @@ +Boost.Utility/IdentityType 1.0.0

Boost.Utility/IdentityType 1.0.0

Lorenzo Caminiti

+ Distributed under the Boost Software License, Version 1.0 (see accompanying + file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt) +

+ This library allows to wrap type expressions within round parenthesis so they + can be passed to macros even when they contain commas. +

+ Consider the following macro which declares a variable named varn with the specified + type (see also var_err.cpp): +

+

#define VAR(type, n) type var ## n
+
+VAR( int, 1 );                  // OK.
+VAR( std::map<int, char>, 2 );  // Error.
+

+

+ The first macro invocation works correctly declaring a variable named var1 of type int. + However, the second macro invocation fails generating a preprocessor error + similar to the following: +

error: macro "VAR" passed 3 arguments, but takes just 2
+

+ That is because the std::map type passed as the first macro parameter + contains a comma , not wrapped + by round parenthesis (). 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: +

  1. + std::map<int +
  2. + char> +
  3. + 2 +

+ Note that, differently from the compiler, the preprocessor only recognizes + round parameters (). Angular + <> or squared [] parenthesis are not used by the preprocessor + when parsing the macro parameters. +

+ In some cases, it might be possible to workaround this issue by avoiding to + pass the type expression to the macro all together. For example, in some cases + a typedef can be used to specify + the type expression with the commas outside the macro (see also var.cpp): +

+

typedef std::map<int, char> map_type;
+VAR( map_type, 3 ); // OK.
+

+

+ When this is not possible or desired (e.g., see the function template f in the section below), the library header + boost/utility/identity_type.hpp + defines a macro BOOST_IDENTITY_TYPE + which can be used to workaround the issue while keeping the type expression + as one of the macro parameters (see also var.cpp). +

+

#include <boost/utility/identity_type.hpp>
+
+VAR( BOOST_IDENTITY_TYPE((std::map<int, char>)), 4 ); // OK.
+

+

+ This macro expands to an expression that evaluates (at compile-time) to the + specified type. The specified type is never split into multiple macro parameters + because it is always wrapped by a set of extra round parenthesis (). 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((...)). +

+ This macro works on any C++03 + compiler (because it does not use variadic + macros). [1] +

+ This macro must be prefixed by typename + when used within templates. For example, let's program a macro that declares + a function parameter named argn + with the specified type (see also template.cpp): +

+

#define ARG(type, n) type arg ## n
+
+template<typename T>
+void f( // Prefix macro with `typename` in templates.
+    ARG( typename BOOST_IDENTITY_TYPE((std::map<int, T>)), 1 )
+) {
+    std::cout << arg1[0] << std::endl;
+}
+

+

+

std::map<int, char> a;
+a[0] = 'a';
+
+f<char>(a); // OK.
+// f(a);    // But error.
+

+

+ However, note that the template parameter type char + must be explicitly specified when invoking the function f<char>(a). In fact, + when the BOOST_IDENTITY_TYPE + macro is used to wrap a function template parameter, the template parameter + can no longer be implicitly determined by the compiler form the function call + as in f(a). (This + limitation does not apply to class templates because class template parameters + must always be explicitly specified.) In other words, without using the BOOST_IDENTITY_TYPE macro, C++ would + normally be able to implicitly deduce the function template parameter as shown + below: +

+

template<typename T>
+void g(
+    std::map<int, T> arg1
+) {
+    std::cout << arg1[0] << std::endl;
+}
+

+

+

g<char>(a); // OK.
+g(a);       // Also OK.
+

+

+ On some compilers (e.g., GCC), using this macro on abstract types (i.e., a + class with one or more pure virtual functions) generates a compiler error. + This can be worked around by manipulating the type adding and removing a reference + to it. +

+ Let's program a macro that performs a static assertion on a Template + Meta-Programming (TMP) meta-function (similarly to Boost.MPL BOOST_MPL_ASSERT). The 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). 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 tmp_assert.cpp): +

+

#define TMP_ASSERT(metafunction) \
+    BOOST_STATIC_ASSERT(metafunction::value)
+
+template<typename T, bool b>
+struct abstract {
+    static const bool value = b;
+    virtual void f(T const& x) = 0;
+};
+
+TMP_ASSERT(
+    boost::remove_reference<            // Add and remove
+        BOOST_IDENTITY_TYPE((           // reference for
+            boost::add_reference<       // abstract type.
+                abstract<int, true>
+            >::type
+        ))
+    >::type
+);
+

+

+ The BOOST_IDENTITY_TYPE macro + can be used either in the call of the user-defined macro (as shown by the examples + so far), or internally to the definition of the user macro. When BOOST_IDENTITY_TYPE is used internally, + the call of the user macro will only have to specify the extra parenthesis + (see also tmp_assert.cpp): +

+

#define TMP_ASSERT_PAREN(parenthesized_metafunction) \
+    /* use `BOOST_IDENTITY_TYPE` in macro definition instead of invocation */ \
+    BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value)
+
+TMP_ASSERT_PAREN(( boost::is_const<std::map<int, char> const> ));
+TMP_ASSERT( BOOST_IDENTITY_TYPE((boost::is_const<std::map<int, char> const>)) );
+

+

+ However, note that the user will always have to specify + the extra parenthesis even when the macro parameters contain no comma: +

+

TMP_ASSERT_PAREN(( boost::is_const<int const> )); // Always extra `()`.
+TMP_ASSERT( boost::is_const<int const> ); // No extra `()` and no macro.
+

+

+ In some cases, using BOOST_IDENTITY_TYPE + internally might provide the best syntax for the user. 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 BOOST_IDENTITY_TYPE: +

BOOST_MPL_ASSERT(( // Natural syntax.
+    boost::mpl::and_<
+          boost::is_const<T>
+        , boost::is_reference<T>
+    >
+));
+

+ However, in other situations it might be preferable to not require the extra + parenthesis in common cases and handle commas as special cases using the BOOST_IDENTITY_TYPE. For example, this + is the case for BOOST_LOCAL_FUNCTION + for which always requiring the extra parenthesis ((...)) + around the types would lead to an unnatural syntax for the local function parameter + types: +

int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax.
+    return x + y;
+} BOOST_LOCAL_FUNCTION_NAME(add)
+

+ Instead requiring the user to specify BOOST_IDENTITY_TYPE + 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. +

+ The implementation of this library macro is equivalent to the following: [2] +

#include <boost/type_traits/function_traits.hpp>
+
+#define BOOST_IDENTITY_TYPE(parenthesized_type) \
+    boost::function_traits<void parenthesized_type>::arg1_type
+

+ Essentially, the type is wrapped between round parenthesis (std::map<int, + char>) + so it can be passed as a macro parameter even if it contain commas. 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>). Finally, the type of the first argument + arg1_type is extracted therefore + obtaining the original type from the parenthesized type (effectively stripping + the parenthesis from around the type). +

Reference

Wrap type expressions with round parenthesis so they can be passed to macros even if they contain commas.

+
+BOOST_IDENTITY_TYPE(parenthesized_type)

Macro BOOST_IDENTITY_TYPE

BOOST_IDENTITY_TYPE — This macro allows to wrap the specified type expression within extra round parenthesis so the type can be passed as a single macro parameter even if it contains commas (not already wrapped within round parenthesis).

Synopsis

// In header: <boost/utility/identity_type.hpp>
+
+BOOST_IDENTITY_TYPE(parenthesized_type)

Description

Parameters:

parenthesized_typeThe type expression to be passed as macro parameter wrapped by a single set of round parenthesis (...). This type expression can contain an arbitrary number of commas.

+

This macro works on any C++03 compiler (it does not require variadic macros).

This macro must be prefixed by typename when used within templates. However, the compiler will not be able to automatically determine function template parameters when they are wrapped with this macro (these parameters need to be explicitly specified when calling the function template).

On some compilers (like GCC), using this macro on an abstract types requires to add and remove a reference to the type.



[1] + Using variadic macros, it would be possible to use a single set of 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). +

[2] + There is absolutely no guarantee that the macro is actually implemented using + the code listed in this documentation. This code is for explanatory purposes + only. +

diff --git a/identity_type/doc/identity_type.qbk b/identity_type/doc/identity_type.qbk new file mode 100644 index 0000000..d5107a3 --- /dev/null +++ b/identity_type/doc/identity_type.qbk @@ -0,0 +1,159 @@ + +[/ Copyright (C) 2009-2012 Lorenzo Caminiti ] +[/ Distributed under the Boost Software License, Version 1.0 ] +[/ (see accompanying file LICENSE_1_0.txt or a copy at ] +[/ http://www.boost.org/LICENSE_1_0.txt) ] +[/ Home at http://www.boost.org/libs/utility/identity_type ] + +[library Boost.Utility/IdentityType + [quickbook 1.5] + [version 1.0.0] + [copyright 2009-2012 Lorenzo Caminiti] + [purpose wraps types with round parenthesis] + [license + Distributed under the Boost Software License, Version 1.0 + (see accompanying file LICENSE_1_0.txt or a copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] + [authors [Caminiti lorcaminiti@gmail.com, Lorenzo]] + [category Utilities] +] + +This library allows to wrap type expressions within round parenthesis so they can be passed to macros even when they contain commas. + +[import ../test/var_err.cpp] +[import ../test/var.cpp] +[import ../test/template.cpp] +[import ../test/tmp_assert.cpp] + +[section Motivation] + +Consider the following macro which declares a variable named `var`/n/ with the specified /type/ (see also [@../../test/var_err.cpp =var_err.cpp=]): + +[var_err] + +The first macro invocation works correctly declaring a variable named `var1` of type `int`. +However, the second macro invocation fails generating a preprocessor error similar to the following: + +[pre + error: macro "VAR" passed 3 arguments, but takes just 2 +] + +That is because the `std::map` type passed as the first macro parameter contains a comma `,` not wrapped by round parenthesis `()`. +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: + +# `std::map` +# `2` + +Note that, differently from the compiler, the preprocessor only recognizes round parameters `()`. +Angular `<>` or squared `[]` parenthesis are not used by the preprocessor when parsing the macro parameters. + +[endsect] + +[section Solution] + +In some cases, it might be possible to workaround this issue by avoiding to pass the type expression to the macro all together. +For example, in some cases a `typedef` can be used to specify the type expression with the commas outside the macro (see also [@../../test/var.cpp =var.cpp=]): + +[var_typedef] + +When this is not possible or desired (e.g., see the function template `f` in the section below), the 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=]). + +[var_ok] + +This macro expands to an expression that evaluates (at compile-time) to the specified type. +The specified type is never split into multiple macro parameters because it is always wrapped by a set of extra round parenthesis `()`. +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((...))`. + +This macro works on any [@http://www.open-std.org/JTC1/SC22/WG21/docs/standards C++03] compiler (because it does not use [@http://en.wikipedia.org/wiki/Variadic_macro variadic macros]). +[footnote +Using variadic macros, it would be possible to use a single set of 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). +] + +[endsect] + +[section Templates] + +This macro must be prefixed by `typename` when used within templates. +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=]): + +[template_f_decl] +[template_f_call] + +However, note that the template parameter type `char` must be explicitly specified when invoking the function `f(a)`. +In fact, when the [macroref BOOST_IDENTITY_TYPE] macro is used to wrap a function template parameter, the template parameter can no longer be implicitly determined by the compiler form the function call as in `f(a)`. +(This limitation does not apply to class templates because class template parameters must always be explicitly specified.) +In other words, without using the [macroref BOOST_IDENTITY_TYPE] macro, C++ would normally be able to implicitly deduce the function template parameter as shown below: + +[template_g_decl] +[template_g_call] + +[endsect] + +[section Abstract Types] + +On some compilers (e.g., GCC), using this macro on abstract types (i.e., a class with one or more pure virtual functions) generates a compiler error. +This can be worked around by manipulating the type adding and removing a reference to it. + +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`]). +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). +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/tmp_assert.cpp =tmp_assert.cpp=]): + +[tmp_assert_abstract] + +[endsect] + +[section Annex: Usage] + +The [macroref BOOST_IDENTITY_TYPE] macro can be used either in the call of the user-defined macro (as shown by the examples so far), or internally to the definition of the user macro. +When [macroref BOOST_IDENTITY_TYPE] is used internally, the call of the user macro will only have to specify the extra parenthesis (see also [@../../test/tmp_assert.cpp =tmp_assert.cpp=]): + +[tmp_assert_alternative] + +However, note that the user will /always/ have to specify the extra parenthesis even when the macro parameters contain no comma: + +[tmp_assert_alternative_always] + +In some cases, using [macroref BOOST_IDENTITY_TYPE] internally might provide the best syntax for the user. +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]: + + BOOST_MPL_ASSERT(( // Natural syntax. + boost::mpl::and_< + boost::is_const + , boost::is_reference + > + )); + +However, in other situations it might be preferable to not require the extra parenthesis in common cases and handle commas as special cases using the [macroref BOOST_IDENTITY_TYPE]. +For example, this is the case for `BOOST_LOCAL_FUNCTION` for which always requiring the extra parenthesis `((...))` around the types would lead to an unnatural syntax for the local function parameter types: + + int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax. + return x + y; + } BOOST_LOCAL_FUNCTION_NAME(add) + +Instead requiring the user to specify [macroref BOOST_IDENTITY_TYPE] 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. + +[endsect] + +[section Annex: Implementation] + +The implementation of this library macro is equivalent to the following: +[footnote +There is absolutely no guarantee that the macro is actually implemented using the code listed in this documentation. +This code is for explanatory purposes only. +] + + #include + + #define BOOST_IDENTITY_TYPE(parenthesized_type) \ + boost::function_traits::arg1_type + +Essentially, the type is wrapped between round parenthesis `(std::map)` so it can be passed as a macro parameter even if it contain commas. +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)`. +Finally, the type of the first argument `arg1_type` is extracted therefore obtaining the original type from the parenthesized type (effectively stripping the parenthesis from around the type). + +[endsect] + +[xinclude reference.xml] + diff --git a/identity_type/index.html b/identity_type/index.html new file mode 100644 index 0000000..00b3362 --- /dev/null +++ b/identity_type/index.html @@ -0,0 +1,15 @@ + + + + + + + Automatic redirection failed, click this + link  
+

© Copyright Lorenzo Caminiti, 2009-2012

+

Distributed under the Boost Software License, Version 1.0 (see + accompanying file + LICENSE_1_0.txt or a copy at + www.boost.org/LICENSE_1_0.txt)

+ + diff --git a/identity_type/test/Jamfile.v2 b/identity_type/test/Jamfile.v2 new file mode 100644 index 0000000..2f0bdac --- /dev/null +++ b/identity_type/test/Jamfile.v2 @@ -0,0 +1,14 @@ + +# Copyright (C) 2009-2012 Lorenzo Caminiti +# Distributed under the Boost Software License, Version 1.0 +# (see accompanying file LICENSE_1_0.txt or a copy at +# http://www.boost.org/LICENSE_1_0.txt) +# Home at http://www.boost.org/libs/utility/identity_type + +import testing ; + +compile-fail var_err.cpp ; +run var.cpp ; +run template.cpp ; +run tmp_assert.cpp ; + diff --git a/identity_type/test/template.cpp b/identity_type/test/template.cpp new file mode 100644 index 0000000..ec42628 --- /dev/null +++ b/identity_type/test/template.cpp @@ -0,0 +1,48 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/utility/identity_type + +#include +#include +#include + +//[template_f_decl +#define ARG(type, n) type arg ## n + +template +void f( // Prefix macro with `typename` in templates. + ARG( typename BOOST_IDENTITY_TYPE((std::map)), 1 ) +) { + std::cout << arg1[0] << std::endl; +} +//] + +//[template_g_decl +template +void g( + std::map arg1 +) { + std::cout << arg1[0] << std::endl; +} +//] + +int main() { + //[template_f_call + std::map a; + a[0] = 'a'; + + f(a); // OK. + // f(a); // But error. + //] + + //[template_g_call + g(a); // OK. + g(a); // Also OK. + //] + + return 0; +} + diff --git a/identity_type/test/tmp_assert.cpp b/identity_type/test/tmp_assert.cpp new file mode 100644 index 0000000..17755cb --- /dev/null +++ b/identity_type/test/tmp_assert.cpp @@ -0,0 +1,51 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/utility/identity_type + +#include +#include +#include +#include +#include +#include + +//[tmp_assert_abstract +#define TMP_ASSERT(metafunction) \ + BOOST_STATIC_ASSERT(metafunction::value) + +template +struct abstract { + static const bool value = b; + virtual void f(T const& x) = 0; +}; + +TMP_ASSERT( + boost::remove_reference< // Add and remove + BOOST_IDENTITY_TYPE(( // reference for + boost::add_reference< // abstract type. + abstract + >::type + )) + >::type +); +//] + +//[tmp_assert_alternative +#define TMP_ASSERT_PAREN(parenthesized_metafunction) \ + /* use `BOOST_IDENTITY_TYPE` in macro definition instead of invocation */ \ + BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value) + +TMP_ASSERT_PAREN(( boost::is_const const> )); +TMP_ASSERT( BOOST_IDENTITY_TYPE((boost::is_const const>)) ); +//] + +//[tmp_assert_alternative_always +TMP_ASSERT_PAREN(( boost::is_const )); // Always extra `()`. +TMP_ASSERT( boost::is_const ); // No extra `()` and no macro. +//] + +int main() { return 0; } + diff --git a/identity_type/test/var.cpp b/identity_type/test/var.cpp new file mode 100644 index 0000000..896aa03 --- /dev/null +++ b/identity_type/test/var.cpp @@ -0,0 +1,26 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/utility/identity_type + +#include + +#define VAR(type, n) type var ## n + +VAR( int, 1 ); // OK. + +//[var_typedef +typedef std::map map_type; +VAR( map_type, 3 ); // OK. +//] + +//[var_ok +#include + +VAR( BOOST_IDENTITY_TYPE((std::map)), 4 ); // OK. +//] + +int main() { return 0; } + diff --git a/identity_type/test/var_err.cpp b/identity_type/test/var_err.cpp new file mode 100644 index 0000000..7ba0c52 --- /dev/null +++ b/identity_type/test/var_err.cpp @@ -0,0 +1,18 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/utility/identity_type + +#include + +//[var_err +#define VAR(type, n) type var ## n + +VAR( int, 1 ); // OK. +VAR( std::map, 2 ); // Error. +//] + +int main() { return 0; } + From d6cb9a9176294bf42507cfe062ba97d799b11966 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Thu, 16 Feb 2012 18:24:34 +0000 Subject: [PATCH 4/8] Fixed a bug in BOOST_LOCAL_FUNCTION_DETAIL_PP_VOID_LIST: a typo VOId -> VOID. Fixed a bug in scope_exit.hpp: An extra trailing \ in a macro definition (compiled only when BOOST_NO_VARIADIC_MACROS is defined). Renamed LocalFunction and ScopeExit tests and examples from _err to _error. Updated LocalFunction docs. [SVN r77042] --- identity_type/doc/identity_type.qbk | 6 +++--- identity_type/test/Jamfile.v2 | 2 +- identity_type/test/{var_err.cpp => var_error.cpp} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename identity_type/test/{var_err.cpp => var_error.cpp} (97%) diff --git a/identity_type/doc/identity_type.qbk b/identity_type/doc/identity_type.qbk index d5107a3..2723d33 100644 --- a/identity_type/doc/identity_type.qbk +++ b/identity_type/doc/identity_type.qbk @@ -21,16 +21,16 @@ This library allows to wrap type expressions within round parenthesis so they can be passed to macros even when they contain commas. -[import ../test/var_err.cpp] +[import ../test/var_error.cpp] [import ../test/var.cpp] [import ../test/template.cpp] [import ../test/tmp_assert.cpp] [section Motivation] -Consider the following macro which declares a variable named `var`/n/ with the specified /type/ (see also [@../../test/var_err.cpp =var_err.cpp=]): +Consider the following macro which declares a variable named `var`/n/ with the specified /type/ (see also [@../../test/var_error.cpp =var_error.cpp=]): -[var_err] +[var_error] The first macro invocation works correctly declaring a variable named `var1` of type `int`. However, the second macro invocation fails generating a preprocessor error similar to the following: diff --git a/identity_type/test/Jamfile.v2 b/identity_type/test/Jamfile.v2 index 2f0bdac..482c0c0 100644 --- a/identity_type/test/Jamfile.v2 +++ b/identity_type/test/Jamfile.v2 @@ -7,7 +7,7 @@ import testing ; -compile-fail var_err.cpp ; +compile-fail var_error.cpp ; run var.cpp ; run template.cpp ; run tmp_assert.cpp ; diff --git a/identity_type/test/var_err.cpp b/identity_type/test/var_error.cpp similarity index 97% rename from identity_type/test/var_err.cpp rename to identity_type/test/var_error.cpp index 7ba0c52..b69817d 100644 --- a/identity_type/test/var_err.cpp +++ b/identity_type/test/var_error.cpp @@ -7,7 +7,7 @@ #include -//[var_err +//[var_error #define VAR(type, n) type var ## n VAR( int, 1 ); // OK. From 0db9276e8c635c3d935287cb97accd94ed7ecd6c Mon Sep 17 00:00:00 2001 From: Daryle Walker Date: Fri, 17 Feb 2012 01:55:33 +0000 Subject: [PATCH 5/8] Fixed (hopefully) conflict between boost::base_from_member's C++11 constructor template and the automatically defined non-template copy- and/or move-constructors. [SVN r77046] --- base_from_member.html | 24 ++++---- include/boost/utility/base_from_member.hpp | 64 +++++++++++++++++++++- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/base_from_member.html b/base_from_member.html index df4add2..07e144e 100644 --- a/base_from_member.html +++ b/base_from_member.html @@ -174,16 +174,18 @@ value of zero if it is omitted. The class template has a protected data member called member that the derived class can use for later base classes (or itself).

-

If the variadic template arguments and r-value reference features of C++2011 -are present, there will be a single constructor template. It implements -"perfect forwarding" to the best constructor call of -member (if any). The constructor template is marked both -constexpr and explicit. The former will be ignored -if the corresponding inner constructor call (of member) does not -have the marker. The latter binds the other way; always taking effect, even -when the inner constructor call does not have the marker. The constructor -template propagates the noexcept status of the inner constructor -call.

+

If the appropriate features of C++2011 are present, there will be a single +constructor template. It implements "perfect forwarding" to the best +constructor call of member (if any). The constructor template is +marked both constexpr and explicit. The former will +be ignored if the corresponding inner constructor call (of member) +does not have the marker. The latter binds the other way; always taking +effect, even when the inner constructor call does not have the marker. The +constructor template propagates the noexcept status of the inner +constructor call. (The constructor template has a trailing parameter with a +default value that disables the template when its signature is too close to the +signatures of the automatically-defined non-template copy- and/or +move-constructors of base_from_member.)

On earlier-standard compilers, there is a default constructor and several constructor member templates. These constructor templates can take as many @@ -385,7 +387,7 @@ a constructor call but std::nullptr_t cannot.)


-

Revised: 11 February 2012

+

Revised: 16 February 2012

Copyright 2001, 2003, 2004, 2012 Daryle Walker. Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying diff --git a/include/boost/utility/base_from_member.hpp b/include/boost/utility/base_from_member.hpp index 8148077..8d17522 100644 --- a/include/boost/utility/base_from_member.hpp +++ b/include/boost/utility/base_from_member.hpp @@ -15,6 +15,10 @@ #include #include #include +#include +#include +#include +#include // Base-from-member arity configuration macro ------------------------------// @@ -54,6 +58,59 @@ namespace boost { +namespace detail +{ + +// Type-unmarking class template -------------------------------------------// + +// Type-trait to get the raw type, i.e. the type without top-level reference nor +// cv-qualification, from a type expression. Mainly for function arguments, any +// reference part is stripped first. + +// Contributed by Daryle Walker + +template < typename T > +struct remove_cv_ref +{ + typedef typename ::boost::remove_cv::type>::type type; + +}; // boost::detail::remove_cv_ref + +// Unmarked-type comparison class template ---------------------------------// + +// Type-trait to check if two type expressions have the same raw type. + +// Contributed by Daryle Walker, based on a work-around by Luc Danton + +template < typename T, typename U > +struct is_related + : public ::boost::is_same< + typename ::boost::detail::remove_cv_ref::type, + typename ::boost::detail::remove_cv_ref::type > +{}; + +// Enable-if-on-unidentical-unmarked-type class template -------------------// + +// Enable-if on the first two type expressions NOT having the same raw type. + +// Contributed by Daryle Walker, based on a work-around by Luc Danton + +#ifndef BOOST_NO_VARIADIC_TEMPLATES +template +struct enable_if_unrelated + : public ::boost::enable_if_c +{}; + +template +struct enable_if_unrelated + : public ::boost::disable_if< ::boost::detail::is_related > +{}; +#endif + +} // namespace boost::detail + + // Base-from-member class template -----------------------------------------// // Helper to initialize a base object so a derived class can use this @@ -69,8 +126,11 @@ class base_from_member protected: MemberType member; -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) - template +#if !defined(BOOST_NO_RVALUE_REFERENCES) && \ + !defined(BOOST_NO_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template ::type> explicit BOOST_CONSTEXPR base_from_member( T&& ...x ) BOOST_NOEXCEPT_IF( BOOST_NOEXCEPT_EXPR(::new ((void*) 0) MemberType( static_cast(x)... )) ) // no std::is_nothrow_constructible... From 2891cb52d6ff086e24e6bf79c284eb71e7e1ad9c Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Fri, 17 Feb 2012 21:02:00 +0000 Subject: [PATCH 6/8] Added Boost.Utility/IdentityType and Boost.Functional/OverloadedFunction to status/Jamfile.v2 list of regression tests. Updated Boost.ScopeExit documentation. [SVN r77059] --- identity_type/doc/html/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/identity_type/doc/html/index.html b/identity_type/doc/html/index.html index c0dc1ee..240c80d 100644 --- a/identity_type/doc/html/index.html +++ b/identity_type/doc/html/index.html @@ -8,7 +8,7 @@ can be passed to macros even when they contain commas.

Consider the following macro which declares a variable named varn with the specified - type (see also var_err.cpp): + type (see also var_error.cpp):

#define VAR(type, n) type var ## n
 
@@ -215,7 +215,7 @@
 
 BOOST_IDENTITY_TYPE(parenthesized_type)

Macro BOOST_IDENTITY_TYPE

BOOST_IDENTITY_TYPE — This macro allows to wrap the specified type expression within extra round parenthesis so the type can be passed as a single macro parameter even if it contains commas (not already wrapped within round parenthesis).

Synopsis

// In header: <boost/utility/identity_type.hpp>
 
-BOOST_IDENTITY_TYPE(parenthesized_type)

Description

Parameters:

parenthesized_typeThe type expression to be passed as macro parameter wrapped by a single set of round parenthesis (...). This type expression can contain an arbitrary number of commas.

+BOOST_IDENTITY_TYPE(parenthesized_type)

Description

Parameters:

parenthesized_typeThe type expression to be passed as macro parameter wrapped by a single set of round parenthesis (...). This type expression can contain an arbitrary number of commas.

This macro works on any C++03 compiler (it does not require variadic macros).

This macro must be prefixed by typename when used within templates. However, the compiler will not be able to automatically determine function template parameters when they are wrapped with this macro (these parameters need to be explicitly specified when calling the function template).

On some compilers (like GCC), using this macro on an abstract types requires to add and remove a reference to the type.



[1] Using variadic macros, it would be possible to use a single set of parenthesis BOOST_IDENTITY_TYPE(type) instead of two BOOST_IDENTITY_TYPE((type)) From 54c78121c2338a84e3516a64439a98e2a5b5cfe3 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Sat, 18 Feb 2012 19:29:35 +0000 Subject: [PATCH 7/8] Updated ScopeExit "world" tests making person a struct instead of a class. Added a code comment to Utility/IdentityType tmp_assert test. [SVN r77071] --- identity_type/test/tmp_assert.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/identity_type/test/tmp_assert.cpp b/identity_type/test/tmp_assert.cpp index 17755cb..f482999 100644 --- a/identity_type/test/tmp_assert.cpp +++ b/identity_type/test/tmp_assert.cpp @@ -19,7 +19,7 @@ template struct abstract { static const bool value = b; - virtual void f(T const& x) = 0; + virtual void f(T const& x) = 0; // Pure virtual function. }; TMP_ASSERT( @@ -38,13 +38,15 @@ TMP_ASSERT( /* use `BOOST_IDENTITY_TYPE` in macro definition instead of invocation */ \ BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value) +// Specify only extra parenthesis `((...))`. TMP_ASSERT_PAREN(( boost::is_const const> )); +// Specify both the extra parenthesis `((...))` and `BOOST_IDENTITY_TYPE` macro. TMP_ASSERT( BOOST_IDENTITY_TYPE((boost::is_const const>)) ); //] //[tmp_assert_alternative_always -TMP_ASSERT_PAREN(( boost::is_const )); // Always extra `()`. -TMP_ASSERT( boost::is_const ); // No extra `()` and no macro. +TMP_ASSERT_PAREN(( boost::is_const )); // Always extra `((...))`. +TMP_ASSERT( boost::is_const ); // No extra `((...))` and no macro. //] int main() { return 0; } From 5825b6c3299ed9079438976f0245ed70933434a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Mon, 20 Feb 2012 20:17:07 +0000 Subject: [PATCH 8/8] Fixed test indentation and updated docs. [SVN r77080] --- identity_type/doc/html/index.html | 119 +++++++++++++++------------- identity_type/doc/identity_type.qbk | 33 ++++---- identity_type/test/template.cpp | 10 +-- identity_type/test/tmp_assert.cpp | 8 +- identity_type/test/var.cpp | 6 +- identity_type/test/var_error.cpp | 4 +- 6 files changed, 96 insertions(+), 84 deletions(-) diff --git a/identity_type/doc/html/index.html b/identity_type/doc/html/index.html index 240c80d..cc6f4b5 100644 --- a/identity_type/doc/html/index.html +++ b/identity_type/doc/html/index.html @@ -7,13 +7,14 @@ This library allows to wrap type expressions within round parenthesis so they can be passed to macros even when they contain commas.

- Consider the following macro which declares a variable named varn with the specified - type (see also var_error.cpp): + Consider the following macro which declares a variable named varn + with the specified type (see also + var_error.cpp):

#define VAR(type, n) type var ## n
 
-VAR( int, 1 );                  // OK.
-VAR( std::map<int, char>, 2 );  // Error.
+VAR(int, 1);                    // OK.
+VAR(std::map<int, char>, 2);    // Error.
 

The first macro invocation works correctly declaring a variable named var1 of type int. @@ -45,7 +46,7 @@ the type expression with the commas outside the macro (see also var.cpp):

typedef std::map<int, char> map_type;
-VAR( map_type, 3 ); // OK.
+VAR(map_type, 3); // OK.
 

When this is not possible or desired (e.g., see the function template f in the section below), the library header @@ -56,7 +57,7 @@

#include <boost/utility/identity_type.hpp>
 
-VAR( BOOST_IDENTITY_TYPE((std::map<int, char>)), 4 ); // OK.
+VAR(BOOST_IDENTITY_TYPE((std::map<int, char>)), 4); // OK.
 

This macro expands to an expression that evaluates (at compile-time) to the @@ -71,14 +72,15 @@

This macro must be prefixed by typename when used within templates. For example, let's program a macro that declares - a function parameter named argn - with the specified type (see also template.cpp): + a function parameter named argn + with the specified type (see also + template.cpp):

#define ARG(type, n) type arg ## n
 
 template<typename T>
 void f( // Prefix macro with `typename` in templates.
-    ARG( typename BOOST_IDENTITY_TYPE((std::map<int, T>)), 1 )
+    ARG(typename BOOST_IDENTITY_TYPE((std::map<int, T>)), 1)
 ) {
     std::cout << arg1[0] << std::endl;
 }
@@ -87,20 +89,20 @@
 

std::map<int, char> a;
 a[0] = 'a';
 
-f<char>(a); // OK.
-// f(a);    // But error.
+f<char>(a); // OK...
+// f(a);    // ... but error.
 

- However, note that the template parameter type char - must be explicitly specified when invoking the function f<char>(a). In fact, + However, note that the template parameter char + must be manually specified when invoking the function f<char>(a). In fact, when the BOOST_IDENTITY_TYPE macro is used to wrap a function template parameter, the template parameter - can no longer be implicitly determined by the compiler form the function call - as in f(a). (This - limitation does not apply to class templates because class template parameters - must always be explicitly specified.) In other words, without using the BOOST_IDENTITY_TYPE macro, C++ would - normally be able to implicitly deduce the function template parameter as shown - below: + can no longer be automatically deduced by the compiler form the function call + as in f(a). [2] (This limitation does not apply to class templates because class + template parameters must always be explicitly specified.) In other words, without + using the BOOST_IDENTITY_TYPE + macro, C++ would normally be able to automatically deduce the function template + parameter as shown below:

template<typename T>
 void g(
@@ -110,14 +112,14 @@
 }
 

-

g<char>(a); // OK.
-g(a);       // Also OK.
+

g<char>(a); // OK...
+g(a);       // ... and also OK.
 

- On some compilers (e.g., GCC), using this macro on abstract types (i.e., a - class with one or more pure virtual functions) generates a compiler error. - This can be worked around by manipulating the type adding and removing a reference - to it. + 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. This can + be worked around by manipulating the type adding and removing a reference to + it.

Let's program a macro that performs a static assertion on a Template Meta-Programming (TMP) meta-function (similarly to Boost.MPL BOOST_MPL_ASSERT). The BOOST_IDENTITY_TYPE macro can be used @@ -132,7 +134,7 @@ template<typename T, bool b> struct abstract { static const bool value = b; - virtual void f(T const& x) = 0; + virtual void f(T const& x) = 0; // Pure virtual function. }; TMP_ASSERT( @@ -147,29 +149,32 @@

The BOOST_IDENTITY_TYPE macro - can be used either in the call of the user-defined macro (as shown by the examples - so far), or internally to the definition of the user macro. When BOOST_IDENTITY_TYPE is used internally, - the call of the user macro will only have to specify the extra parenthesis - (see also tmp_assert.cpp): + can be used either when calling a user-defined macro (as shown by the examples + so far), or internally in the definition of a user-defined macro (as shown + below). When BOOST_IDENTITY_TYPE + is used in the user macro definition, the call of the user macro will only + have to specify the extra parenthesis (see also tmp_assert.cpp):

#define TMP_ASSERT_PAREN(parenthesized_metafunction) \
     /* use `BOOST_IDENTITY_TYPE` in macro definition instead of invocation */ \
     BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value)
 
-TMP_ASSERT_PAREN(( boost::is_const<std::map<int, char> const> ));
-TMP_ASSERT( BOOST_IDENTITY_TYPE((boost::is_const<std::map<int, char> const>)) );
+// Specify only extra parenthesis `((...))`.
+TMP_ASSERT_PAREN((boost::is_const<std::map<int, char> const>));
+// Specify both the extra parenthesis `((...))` and `BOOST_IDENTITY_TYPE` macro.
+TMP_ASSERT(BOOST_IDENTITY_TYPE((boost::is_const<std::map<int, char> const>)));
 

However, note that the user will always have to specify the extra parenthesis even when the macro parameters contain no comma:

-

TMP_ASSERT_PAREN(( boost::is_const<int const> )); // Always extra `()`.
-TMP_ASSERT( boost::is_const<int const> ); // No extra `()` and no macro.
+

TMP_ASSERT_PAREN((boost::is_const<int const>)); // Always extra `((...))`.
+TMP_ASSERT(boost::is_const<int const>); // No extra `((...))` and no macro.
 

In some cases, using BOOST_IDENTITY_TYPE - internally might provide the best syntax for the user. For example, this is - the case for BOOST_MPL_ASSERT + within the user macro definition might provide the best syntax for the user. + 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 BOOST_IDENTITY_TYPE: @@ -181,22 +186,21 @@ ));

However, in other situations it might be preferable to not require the extra - parenthesis in common cases and handle commas as special cases using the BOOST_IDENTITY_TYPE. For example, this - is the case for BOOST_LOCAL_FUNCTION - for which always requiring the extra parenthesis ((...)) - around the types would lead to an unnatural syntax for the local function parameter - types: + parenthesis in the common cases and handle commas as special cases using BOOST_IDENTITY_TYPE. For example, this + is the case for BOOST_LOCAL_FUNCTION for which always + requiring the extra parenthesis ((...)) + around the types would lead to an unnatural syntax for the local function signature:

int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax.
     return x + y;
 } BOOST_LOCAL_FUNCTION_NAME(add)
 

Instead requiring the user to specify BOOST_IDENTITY_TYPE - when needed allows for the more natural syntax BOOST_LOCAL_FUNCTION(int& + 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.

- The implementation of this library macro is equivalent to the following: [2] + The implementation of this library macro is equivalent to the following: [3]

#include <boost/type_traits/function_traits.hpp>
 
 #define BOOST_IDENTITY_TYPE(parenthesized_type) \
@@ -204,24 +208,29 @@
 

Essentially, the type is wrapped between round parenthesis (std::map<int, char>) - so it can be passed as a macro parameter even if it contain commas. 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 + so it can be passed as a single macro parameter even if it contains commas. + 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>). Finally, the type of the first argument - arg1_type is extracted therefore - obtaining the original type from the parenthesized type (effectively stripping - the parenthesis from around the type). + 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).

Reference

Wrap type expressions with round parenthesis so they can be passed to macros even if they contain commas.

 
 BOOST_IDENTITY_TYPE(parenthesized_type)

Macro BOOST_IDENTITY_TYPE

BOOST_IDENTITY_TYPE — This macro allows to wrap the specified type expression within extra round parenthesis so the type can be passed as a single macro parameter even if it contains commas (not already wrapped within round parenthesis).

Synopsis

// In header: <boost/utility/identity_type.hpp>
 
-BOOST_IDENTITY_TYPE(parenthesized_type)

Description

Parameters:

parenthesized_typeThe type expression to be passed as macro parameter wrapped by a single set of round parenthesis (...). This type expression can contain an arbitrary number of commas.

+BOOST_IDENTITY_TYPE(parenthesized_type)

Description

Parameters:

parenthesized_typeThe type expression to be passed as macro parameter wrapped by a single set of round parenthesis (...). This type expression can contain an arbitrary number of commas.

This macro works on any C++03 compiler (it does not require variadic macros).

This macro must be prefixed by typename when used within templates. However, the compiler will not be able to automatically determine function template parameters when they are wrapped with this macro (these parameters need to be explicitly specified when calling the function template).

On some compilers (like GCC), using this macro on an abstract types requires to add and remove a reference to the type.



[1] - Using variadic macros, it would be possible to use a single set of 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). -

[2] + 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). +

[2] + This is because the implementation of BOOST_IDENTITY_TYPE + wraps the specified type within a meta-function. +

[3] There is absolutely no guarantee that the macro is actually implemented using the code listed in this documentation. This code is for explanatory purposes only. diff --git a/identity_type/doc/identity_type.qbk b/identity_type/doc/identity_type.qbk index 2723d33..3ef0b12 100644 --- a/identity_type/doc/identity_type.qbk +++ b/identity_type/doc/identity_type.qbk @@ -28,7 +28,7 @@ This library allows to wrap type expressions within round parenthesis so they ca [section Motivation] -Consider the following macro which declares a variable named `var`/n/ with the specified /type/ (see also [@../../test/var_error.cpp =var_error.cpp=]): +Consider the following macro which declares a variable named `var`[^['n]] with the specified [^['type]] (see also [@../../test/var_error.cpp =var_error.cpp=]): [var_error] @@ -68,7 +68,7 @@ In fact, a total of two sets of round parenthesis must be used: The parenthesis This macro works on any [@http://www.open-std.org/JTC1/SC22/WG21/docs/standards C++03] compiler (because it does not use [@http://en.wikipedia.org/wiki/Variadic_macro variadic macros]). [footnote -Using variadic macros, it would be possible to use a single set of 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). +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). ] [endsect] @@ -76,15 +76,18 @@ Using variadic macros, it would be possible to use a single set of parenthesis ` [section Templates] This macro must be prefixed by `typename` when used within templates. -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=]): +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=]): [template_f_decl] [template_f_call] -However, note that the template parameter type `char` must be explicitly specified when invoking the function `f(a)`. -In fact, when the [macroref BOOST_IDENTITY_TYPE] macro is used to wrap a function template parameter, the template parameter can no longer be implicitly determined by the compiler form the function call as in `f(a)`. +However, note that the template parameter `char` must be manually specified when invoking the function `f(a)`. +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 in `f(a)`. +[footnote +This is because the implementation of [macroref BOOST_IDENTITY_TYPE] wraps the specified type within a meta-function. +] (This limitation does not apply to class templates because class template parameters must always be explicitly specified.) -In other words, without using the [macroref BOOST_IDENTITY_TYPE] macro, C++ would normally be able to implicitly deduce the function template parameter as shown below: +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: [template_g_decl] [template_g_call] @@ -93,7 +96,7 @@ In other words, without using the [macroref BOOST_IDENTITY_TYPE] macro, C++ woul [section Abstract Types] -On some compilers (e.g., GCC), using this macro on abstract types (i.e., a class with one or more pure virtual functions) generates a compiler error. +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. This can be worked around by manipulating the type adding and removing a reference to it. 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,8 +109,8 @@ In this case, if the meta-function is an abstract type, it needs to be manipulat [section Annex: Usage] -The [macroref BOOST_IDENTITY_TYPE] macro can be used either in the call of the user-defined macro (as shown by the examples so far), or internally to the definition of the user macro. -When [macroref BOOST_IDENTITY_TYPE] is used internally, the call of the user macro will only have to specify the extra parenthesis (see also [@../../test/tmp_assert.cpp =tmp_assert.cpp=]): +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 in the definition of a user-defined macro (as shown below). +When [macroref BOOST_IDENTITY_TYPE] is used in the user macro definition, the call of the user macro will only have to specify the extra parenthesis (see also [@../../test/tmp_assert.cpp =tmp_assert.cpp=]): [tmp_assert_alternative] @@ -115,7 +118,7 @@ However, note that the user will /always/ have to specify the extra parenthesis [tmp_assert_alternative_always] -In some cases, using [macroref BOOST_IDENTITY_TYPE] internally might provide the best syntax for the user. +In some cases, using [macroref BOOST_IDENTITY_TYPE] within the user macro definition might provide the best syntax for the user. 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]: BOOST_MPL_ASSERT(( // Natural syntax. @@ -125,14 +128,14 @@ For example, this is the case for `BOOST_MPL_ASSERT` because the majority of tem > )); -However, in other situations it might be preferable to not require the extra parenthesis in common cases and handle commas as special cases using the [macroref BOOST_IDENTITY_TYPE]. -For example, this is the case for `BOOST_LOCAL_FUNCTION` for which always requiring the extra parenthesis `((...))` around the types would lead to an unnatural syntax for the local function parameter types: +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]. +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: int BOOST_LOCAL_FUNCTION( ((int&)) x, ((int&)) y ) { // Unnatural syntax. return x + y; } BOOST_LOCAL_FUNCTION_NAME(add) -Instead requiring the user to specify [macroref BOOST_IDENTITY_TYPE] 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. +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. [endsect] @@ -149,9 +152,9 @@ This code is for explanatory purposes only. #define BOOST_IDENTITY_TYPE(parenthesized_type) \ boost::function_traits::arg1_type -Essentially, the type is wrapped between round parenthesis `(std::map)` so it can be passed as a macro parameter even if it contain commas. +Essentially, the type is wrapped between round parenthesis `(std::map)` so it can be passed as a single macro parameter even if it contains commas. 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)`. -Finally, the type of the first argument `arg1_type` is extracted therefore obtaining the original type from the parenthesized type (effectively stripping the parenthesis from around the type). +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). [endsect] diff --git a/identity_type/test/template.cpp b/identity_type/test/template.cpp index ec42628..dfc1097 100644 --- a/identity_type/test/template.cpp +++ b/identity_type/test/template.cpp @@ -14,7 +14,7 @@ template void f( // Prefix macro with `typename` in templates. - ARG( typename BOOST_IDENTITY_TYPE((std::map)), 1 ) + ARG(typename BOOST_IDENTITY_TYPE((std::map)), 1) ) { std::cout << arg1[0] << std::endl; } @@ -34,13 +34,13 @@ int main() { std::map a; a[0] = 'a'; - f(a); // OK. - // f(a); // But error. + f(a); // OK... + // f(a); // ... but error. //] //[template_g_call - g(a); // OK. - g(a); // Also OK. + g(a); // OK... + g(a); // ... and also OK. //] return 0; diff --git a/identity_type/test/tmp_assert.cpp b/identity_type/test/tmp_assert.cpp index f482999..b8be643 100644 --- a/identity_type/test/tmp_assert.cpp +++ b/identity_type/test/tmp_assert.cpp @@ -39,14 +39,14 @@ TMP_ASSERT( BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value) // Specify only extra parenthesis `((...))`. -TMP_ASSERT_PAREN(( boost::is_const const> )); +TMP_ASSERT_PAREN((boost::is_const const>)); // Specify both the extra parenthesis `((...))` and `BOOST_IDENTITY_TYPE` macro. -TMP_ASSERT( BOOST_IDENTITY_TYPE((boost::is_const const>)) ); +TMP_ASSERT(BOOST_IDENTITY_TYPE((boost::is_const const>))); //] //[tmp_assert_alternative_always -TMP_ASSERT_PAREN(( boost::is_const )); // Always extra `((...))`. -TMP_ASSERT( boost::is_const ); // No extra `((...))` and no macro. +TMP_ASSERT_PAREN((boost::is_const)); // Always extra `((...))`. +TMP_ASSERT(boost::is_const); // No extra `((...))` and no macro. //] int main() { return 0; } diff --git a/identity_type/test/var.cpp b/identity_type/test/var.cpp index 896aa03..9ed165d 100644 --- a/identity_type/test/var.cpp +++ b/identity_type/test/var.cpp @@ -9,17 +9,17 @@ #define VAR(type, n) type var ## n -VAR( int, 1 ); // OK. +VAR(int, 1); // OK. //[var_typedef typedef std::map map_type; -VAR( map_type, 3 ); // OK. +VAR(map_type, 3); // OK. //] //[var_ok #include -VAR( BOOST_IDENTITY_TYPE((std::map)), 4 ); // OK. +VAR(BOOST_IDENTITY_TYPE((std::map)), 4); // OK. //] int main() { return 0; } diff --git a/identity_type/test/var_error.cpp b/identity_type/test/var_error.cpp index b69817d..efb9743 100644 --- a/identity_type/test/var_error.cpp +++ b/identity_type/test/var_error.cpp @@ -10,8 +10,8 @@ //[var_error #define VAR(type, n) type var ## n -VAR( int, 1 ); // OK. -VAR( std::map, 2 ); // Error. +VAR(int, 1); // OK. +VAR(std::map, 2); // Error. //] int main() { return 0; }