result_of: merge [80445], [80452], [80535], [80550], [80605], [80608] from trunk

[SVN r80621]
This commit is contained in:
Eric Niebler 2012-09-21 18:49:46 +00:00
parent 1920623a4f
commit 7d8353f46a
4 changed files with 432 additions and 9 deletions

View File

@ -58,17 +58,79 @@ struct result_of<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),T))>
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)>
struct cpp0x_result_of_impl<F(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(),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)), 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)

View File

@ -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 @@ namespace detail {
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

View File

@ -129,6 +129,27 @@ struct no_result_type_or_result_template
#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 @@ int main()
#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;
}

View File

@ -143,7 +143,7 @@ void f() {
<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 @@ void f() {
<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&lt;F(T1, T2, ...,
T<em>N</em>)&gt;::type</code> names the type
<code>decltype(boost::declval&lt;F&gt;()(boost::declval&lt;T1&gt;(),
boost::declval&lt;T2&gt;(), ...,
boost::declval&lt;T<em>N</em>&gt;())), as in the
following example.</p>
<blockquote>
<pre>#include &lt;boost/utility/result_of.hpp&gt;
struct functor {
<pre>struct functor {
template&lt;class T&gt;
T operator()(T x)
{
@ -249,7 +253,7 @@ typedef boost::result_of&lt;
<code>result_type</code> and
<code>result&lt;&gt;</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 @@ typedef boost::result_of&lt;
<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> <a href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1454.html">proposal</a>.</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 <a href="#result_of_cxx11_diff">differences</a>
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&lt;
functor(int)
&gt;::type type1; // type1 is int &
typedef boost::result_of&lt;
const functor(int)
&gt;::type type2; // type2 is int const &
typedef boost::result_of&lt;
functor(float&)
&gt;::type type3; // type3 is float &
typedef boost::result_of&lt;
functor(float const&)
&gt;::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&lt;class&gt; struct result;
template&lt;class F&gt;
struct result&lt;F(int)&gt; {
typedef int& type;
};
result&lt;functor(int)&gt;::type operator()(int);
template&lt;class F&gt;
struct result&lt;const F(int)&gt; {
typedef int const& type;
};
result&lt;const functor(int)&gt;::type operator()(int) const;
};</pre>
</blockquote> </li>
<li>Use type transformations to simplify
the <code>result</code> template specialization. For
example, the following uses
<a href="../type_traits/doc/html/index.html">Boost.TypeTraits</a>
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&lt;class&gt; struct result;
template&lt;class F, class T&gt;
struct result&lt;F(T)&gt;
: boost::remove_cv&lt;
typename boost::remove_reference&lt;T&gt;::type
&gt;
{};
template&lt;class T&gt;
T operator()(T const&amp; 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&lt;boost::result_of&lt;functor(short)&gt;::type, int&gt;::value
));
#else
BOOST_STATIC_ASSERT((
boost::is_same&lt;boost::result_of&lt;functor(short)&gt;::type, short&gt;::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&lt;class&gt; struct result {
typedef int type;
};
int operator()();
};
#ifdef BOOST_RESULT_OF_USE_DECLTYPE
BOOST_STATIC_ASSERT((
boost::is_same&lt;boost::result_of&lt;functor()&gt;::type, int&gt;::value
));
#else
BOOST_STATIC_ASSERT((
boost::is_same&lt;boost::result_of&lt;functor()&gt;::type, void&gt;::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&lt;class&gt; struct result;
template&lt;class F, class T&gt; struct result&lt;F(const T)&gt; {
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&lt;
boost::result_of&lt;functor(int const &)&gt;::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&lt;
boost::result_of&lt;functor(const short)&gt;::type,
short
::value
));
#else
BOOST_STATIC_ASSERT((
boost::is_same&lt;
boost::result_of&lt;functor(const short)&gt;::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>