$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r80621 - in branches/release: . boost boost/utility boost/utility/detail libs libs/utility libs/utility/test
From: eric_at_[hidden]
Date: 2012-09-21 14:49:46
Author: eric_niebler
Date: 2012-09-21 14:49:46 EDT (Fri, 21 Sep 2012)
New Revision: 80621
URL: http://svn.boost.org/trac/boost/changeset/80621
Log:
result_of: merge [80445], [80452], [80535], [80550], [80605], [80608] from trunk
Properties modified: 
   branches/release/   (props changed)
   branches/release/boost/   (props changed)
   branches/release/boost/utility/   (props changed)
   branches/release/libs/   (props changed)
   branches/release/libs/utility/   (props changed)
Text files modified: 
   branches/release/boost/utility/detail/result_of_iterate.hpp |    66 +++++++                                 
   branches/release/boost/utility/result_of.hpp                |    18 ++                                      
   branches/release/libs/utility/test/result_of_test.cpp       |    26 +++                                     
   branches/release/libs/utility/utility.htm                   |   331 +++++++++++++++++++++++++++++++++++++++ 
   4 files changed, 432 insertions(+), 9 deletions(-)
Modified: branches/release/boost/utility/detail/result_of_iterate.hpp
==============================================================================
--- branches/release/boost/utility/detail/result_of_iterate.hpp	(original)
+++ branches/release/boost/utility/detail/result_of_iterate.hpp	2012-09-21 14:49:46 EDT (Fri, 21 Sep 2012)
@@ -58,17 +58,79 @@
 
 namespace detail {
 
+#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
+
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+class is_callable<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T))> {
+    typedef char (&pass)[1];
+    typedef char (&fail)[2];
+
+    template<typename G BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+             BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename S)>
+    struct sub {};
+    template<typename S>
+    struct stub {};
+
+    template<typename G BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+             BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename S)>
+    static pass test(sub<G BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+                         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),S)>
+                   , stub<
+                          decltype(
+                              boost::declval<G>()(
+                                  BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), boost::declval<S, >() BOOST_PP_INTERCEPT)
+                              )
+                          )
+                      >* x = 0);
+    static fail test(...);
+
+public:
+    const static bool value = sizeof(pass) == sizeof(test(sub<F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+                                                              BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)
+                                                          >()));
+    typedef typename boost::mpl::bool_<value>::type type;
+};
+
 template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
          BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
-struct cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T))>
+struct cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), true>
+    : lazy_enable_if<
+          is_callable<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T))>
+        , cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), false>
+      >
+{};
+
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+struct cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), false>
 {
   typedef decltype(
     boost::declval<F>()(
-      BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), declval<T, >() BOOST_PP_INTERCEPT)
+      BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), boost::declval<T, >() BOOST_PP_INTERCEPT)
+    )
+  ) type;
+};
+
+#else // BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
+
+template<typename F BOOST_PP_COMMA_IF(BOOST_PP_ITERATION())
+         BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),typename T)>
+struct cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T)), 
+                            typename result_of_always_void<decltype(
+                                boost::declval<F>()(
+                                    BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), boost::declval<T, >() BOOST_PP_INTERCEPT)
+                                )
+                            )>::type> {
+  typedef decltype(
+    boost::declval<F>()(
+      BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), boost::declval<T, >() BOOST_PP_INTERCEPT)
     )
   ) type;
 };
 
+#endif // BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
+
 } // namespace detail 
 
 #else // defined(BOOST_RESULT_OF_USE_DECLTYPE)
Modified: branches/release/boost/utility/result_of.hpp
==============================================================================
--- branches/release/boost/utility/result_of.hpp	(original)
+++ branches/release/boost/utility/result_of.hpp	2012-09-21 14:49:46 EDT (Fri, 21 Sep 2012)
@@ -25,6 +25,7 @@
 #include <boost/type_traits/is_member_function_pointer.hpp>
 #include <boost/type_traits/remove_cv.hpp>
 #include <boost/utility/declval.hpp>
+#include <boost/utility/enable_if.hpp>
 
 #ifndef BOOST_RESULT_OF_NUM_ARGS
 #  define BOOST_RESULT_OF_NUM_ARGS 16
@@ -59,7 +60,22 @@
 BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
 
 template<typename F, typename FArgs, bool HasResultType> struct tr1_result_of_impl;
-template<typename F> struct cpp0x_result_of_impl;
+
+#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
+
+template<typename F> class is_callable;
+template<typename F, bool TestCallability = true> struct cpp0x_result_of_impl;
+
+#else // BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
+
+template<typename T>
+struct result_of_always_void
+{
+    typedef void type;
+};
+template<typename F, typename Enable = void> struct cpp0x_result_of_impl {};
+
+#endif // BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
 
 template<typename F>
 struct result_of_void_impl
Modified: branches/release/libs/utility/test/result_of_test.cpp
==============================================================================
--- branches/release/libs/utility/test/result_of_test.cpp	(original)
+++ branches/release/libs/utility/test/result_of_test.cpp	2012-09-21 14:49:46 EDT (Fri, 21 Sep 2012)
@@ -129,6 +129,27 @@
 #endif
 };
 
+// sfinae_tests are derived from example code from Joel de Guzman,
+// which demonstrated the interaction between result_of and SFINAE.
+template <typename F, typename Arg>
+typename boost::result_of<F(Arg const&)>::type
+sfinae_test(F f, Arg const& arg)
+{
+    return f(arg);
+}
+
+template <typename F, typename Arg>
+typename boost::result_of<F(Arg&)>::type
+sfinae_test(F f, Arg& arg)
+{
+    return f(arg);
+}
+
+int sfinae_test_f(int& i)
+{
+    return i;
+}
+
 struct X {};
 
 int main()
@@ -268,5 +289,10 @@
 #endif
 #endif
 
+#if defined(BOOST_RESULT_OF_USE_DECLTYPE)
+  int i = 123;
+  sfinae_test(sfinae_test_f, i);
+#endif // defined(BOOST_RESULT_OF_USE_DECLTYPE)
+
   return 0;
 }
Modified: branches/release/libs/utility/utility.htm
==============================================================================
--- branches/release/libs/utility/utility.htm	(original)
+++ branches/release/libs/utility/utility.htm	2012-09-21 14:49:46 EDT (Fri, 21 Sep 2012)
@@ -143,7 +143,7 @@
                 <h2><a name="result_of">Class template
                 result_of</a></h2> <p>The class template
                 <code>result_of</code> helps determine the type of a
-                call expression. Given an lvalue <code>f</code> of
+                call expression. For example, given an lvalue <code>f</code> of
                 type <code>F</code> and lvalues <code>t1</code>,
                 <code>t2</code>, ..., <code>t<em>N</em></code> of
                 types <code>T1</code>, <code>T2</code>, ...,
@@ -163,12 +163,16 @@
 
                 <p>If your compiler's support for <code>decltype</code> is
                 adequate, <code>result_of</code> automatically uses it to
-                deduce the result type of your callable object.</p>
+                deduce the type of the call expression, in which case
+                <code>result_of<F(T1, T2, ...,
+                T<em>N</em>)>::type</code> names the type
+                <code>decltype(boost::declval<F>()(boost::declval<T1>(),
+                boost::declval<T2>(), ...,
+                boost::declval<T<em>N</em>>())), as in the
+                following example.</p>
 
                 <blockquote>
-                <pre>#include <boost/utility/result_of.hpp>
-
-struct functor {
+                <pre>struct functor {
     template<class T>
     T operator()(T x)
     {
@@ -249,7 +253,7 @@
                 <code>result_type</code> and
                 <code>result<></code> members accurately
                 represent the return type of
-                <code>operator()</code>.</p>
+                <code>operator()</code> given a call expression.</p>
 
                 <a name="BOOST_NO_RESULT_OF"></a>
                 <p>This implementation of <code>result_of</code>
@@ -266,6 +270,321 @@
                 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf">N1836</a>,
                 or, for motivation and design rationale,
                 the <code>result_of</code> proposal.</p>
+
+                <a name="result_of_guidelines">
+                <h3>Usage guidelines for boost::result_of</h3>
+                </a>
+
+                <p>The following are general suggestions about when
+                and how to use <code>boost::result_of</code>.</p>
+
+                <ol>
+                <li> If you are targeting C++11 and are not concerned
+                about portability to non-compliant compilers or
+                previous versions of the standard, then use
+                <code>std::result_of</code>. If <code>std::result_of</code>
+                meets your needs, then there's no reason to stop using
+                it.</li>
+
+                <li> If you are targeting C++11 but may port your code
+                to legacy compilers at some time in the future, then
+                use <code>boost::result_of</code> with
+                <code>decltype</code>. When <code>decltype</code> is
+                used <code>boost::result_of</code>
+                and <code>std::result_of</code> are usually
+                interchangeable. See the documentation on
+                known differences
+                between boost::result_of and C++11 result_of.</li>
+
+                <li> If compiler portability is required,
+                use <code>boost::result_of</code> with the TR1 protocol.</li>
+                </ol>
+
+                <p>Regardless of how you
+                configure <code>boost::result_of</code>, it is
+                important to bear in mind that the return type of a
+                function may change depending on its arguments, and
+                additionally, the return type of a member function may
+                change depending on the cv-qualification of the
+                object. <code>boost::result_of</code> must be passed
+                the appropriately cv-qualified types in order to
+                deduce the corresponding return type. For example:
+
+                <blockquote>
+                <pre>struct functor {
+    int& operator()(int);
+    int const& operator()(int) const;
+
+    float& operator()(float&);
+    float const& operator()(float const&);
+};
+
+typedef boost::result_of<
+    functor(int)
+>::type type1; // type1 is int &
+
+typedef boost::result_of<
+    const functor(int)
+>::type type2; // type2 is int const &
+
+typedef boost::result_of<
+    functor(float&)
+>::type type3; // type3 is float &
+
+typedef boost::result_of<
+    functor(float const&)
+>::type type4; // type4 is float const &</pre>
+                </blockquote>
+
+                <a name="result_of_tr1_protocol_guidelines">
+                <h3>Usage guidelines for the TR1 result_of protocol</h3>
+                </a>
+
+                <p>On compliant C++11
+                compilers, <code>boost::result_of</code> can
+                use <code>decltype</code> to deduce the type of any
+                call expression, including calls to function
+                objects. However, on pre-C++11 compilers or on
+                compilers without adequate decltype support,
+                additional scaffolding is needed from function
+                objects as described above. The following are
+                suggestions about how to use the TR1 protocol.</p>
+
+                <ul>
+                    <li>When the return type does not depend on the
+                    argument types or the cv-qualification of the
+                    function object, simply
+                    define <code>result_type</code>. There is no need
+                    to use the <code>result</code> template unless the
+                    return type varies.</li>
+
+                    <li>Use the protocol specified type when defining
+                    function prototypes. This can help ensure the
+                    actual return type does not get out of sync with
+                    the protocol specification. For example:
+
+                   <blockquote>
+                   <pre>struct functor {
+    typedef int result_type;
+    result_type operator()(int);
+};</pre>
+                   </blockquote> </li>
+
+                   <li>Always specify the <code>result</code>
+                   specialization near the corresponding
+                   <code>operator()</code> overload. This can make it
+                   easier to keep the specializations in sync with the
+                   overloads. For example:
+
+                   <blockquote>
+                   <pre>struct functor {
+    template<class> struct result;
+
+    template<class F>
+    struct result<F(int)> {
+        typedef int& type;
+    };
+    result<functor(int)>::type operator()(int);
+
+    template<class F>
+    struct result<const F(int)> {
+        typedef int const& type;
+    };
+    result<const functor(int)>::type operator()(int) const;
+};</pre>
+                   </blockquote> </li>
+
+                   <li>Use type transformations to simplify
+                   the <code>result</code> template specialization. For
+                   example, the following uses
+                   Boost.TypeTraits
+                   to specialize the <code>result</code> template for
+                   a single <code>operator()</code> that can be called on
+                   both a const and non-const function object with
+                   either an lvalue or rvalue argument.
+
+                   <blockquote>
+                   <pre>struct functor {
+    template<class> struct result;
+
+    template<class F, class T>
+    struct result<F(T)> 
+        : boost::remove_cv<
+              typename boost::remove_reference<T>::type
+          >
+    {};
+
+    template<class T>
+    T operator()(T const& x) const;
+};</pre>
+                   </blockquote></li>
+                </ul>
+
+                <a name="result_of_tr1_diff">
+                <h3>Known differences between boost::result_of and TR1 result_of</h3>
+                </a>
+
+                When using <code>decltype</code>, <code>boost::result_of</code>
+                ignores the TR1 protocol and instead deduces the
+                return type of function objects directly
+                via <code>decltype</code>. In most situations, users
+                will not notice a difference, so long as they use the
+                protocol correctly. The following are situations in
+                which the type deduced
+                by <code>boost::result_of</code> is known to differ depending on
+                whether <code>decltype</code> or the TR1 protocol is
+                used.
+
+                <ul>
+                <li> TR1 protocol misusage
+
+                     <p>When using the TR1
+                     protocol, <code>boost::result_of</code> cannot
+                     detect whether the actual type of a call to a
+                     function object is the same as the type specified
+                     by the protocol, which allows for the possibility
+                     of inadvertent mismatches between the specified
+                     type and the actual type. When
+                     using <code>decltype</code>, these subtle bugs
+                     may result in compilation errors. For example:</p>
+
+                     <blockquote>
+                     <pre>struct functor {
+   typedef short result_type;
+   int operator()(short);
+};
+
+#ifdef BOOST_RESULT_OF_USE_DECLTYPE
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<boost::result_of<functor(short)>::type, int>::value
+)); 
+
+#else
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<boost::result_of<functor(short)>::type, short>::value
+));
+
+#endif</pre>
+                   </blockquote>
+
+                  <p>Note that the user can
+                  force <code>boost::result_of</code> to use the TR1
+                  protocol even on platforms that
+                  support <code>decltype</code> by
+                  defining <code>BOOST_RESULT_OF_USE_TR1</code>.</p></li>
+
+                  <li> Nullary function objects
+
+                       <p>When using the TR1 protocol, <code>boost::result_of</code>
+                       cannot always deduce the type of calls to
+                       nullary function objects, in which case the
+                       type defaults to void. When using <code>decltype</code>,
+                       <code>boost::result_of</code> always gives the actual type of the
+                       call expression. For example:</p>
+
+                       <blockquote>
+                       <pre>struct functor {
+   template<class> struct result {
+       typedef int type;
+   };
+   int operator()();
+};
+
+#ifdef BOOST_RESULT_OF_USE_DECLTYPE
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<boost::result_of<functor()>::type, int>::value
+));
+
+#else
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<boost::result_of<functor()>::type, void>::value
+));
+
+#endif</pre>
+                       </blockquote>
+
+                       <p>Note that there are some workarounds for the
+                       nullary function problem. So long as the return
+                       type does not vary,
+                       <code>result_type</code> can always be used to
+                       specify the return type regardless of arity. If the
+                       return type does vary, then the user can
+                       specialize <code>boost::result_of</code> itself for
+                       nullary calls.</p></li>
+
+                  <li> Non-class prvalues and cv-qualification
+
+                       <p>When using the TR1
+                       protocol, <code>boost::result_of</code> will
+                       report the cv-qualified type specified
+                       by <code>result_type</code> or
+                       the <code>result</code> template regardless of
+                       the actual cv-qualification of the call
+                       expression. When using
+                       <code>decltype</code>, <code>boost::result_of</code>
+                       will report the actual type of the call expression,
+                       which is not cv-qualified when the expression is a
+                       non-class prvalue. For example:</p>
+
+                       <blockquote>
+                       <pre>struct functor {
+   template<class> struct result;
+   template<class F, class T> struct result<F(const T)> {
+       typedef const T type;
+   };
+
+   const short operator()(const short);
+   int const & operator()(int const &);
+};
+
+// Non-prvalue call expressions work the same with or without decltype.
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<
+       boost::result_of<functor(int const &)>::type,
+       int const &
+::value
+));
+
+// Non-class prvalue call expressions are not actually cv-qualified,
+// but only the decltype-based result_of reports this accurately.
+
+#ifdef BOOST_RESULT_OF_USE_DECLTYPE
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<
+       boost::result_of<functor(const short)>::type,
+       short
+::value
+));
+
+#else
+
+BOOST_STATIC_ASSERT((
+   boost::is_same<
+       boost::result_of<functor(const short)>::type,
+       const short
+::value
+));
+
+#endif</pre>
+                       </blockquote></li>
+                </ul>
+
+                <a name="result_of_cxx11_diff">
+                <h3>Known differences between boost::result_of and C++11 result_of</h3>
+                </a>
+
+                <p>When using <code>decltype</code>, <code>boost::result_of</code>
+                implements most of the C++11 result_of
+                specification. One known exception is that
+                <code>boost::result_of</code> does not implement the
+                requirements regarding pointers to member data.</p>
+
                 <p>Created by Doug Gregor. Contributions from Daniel Walker, Eric Niebler, Michel Morin and others</p>
 
                 <h2>Class templates for the Base-from-Member Idiom</h2>