diff --git a/utility.htm b/utility.htm index 73bd692..c46c515 100644 --- a/utility.htm +++ b/utility.htm @@ -143,7 +143,7 @@ void f() {
The class template
result_of
helps determine the type of a
- call expression. Given an lvalue f
of
+ call expression. For example, given an lvalue f
of
type F
and lvalues t1
,
t2
, ..., tN
of
types T1
, T2
, ...,
@@ -163,12 +163,16 @@ void f() {
If your compiler's support for decltype
is
adequate, result_of
automatically uses it to
- deduce the result type of your callable object.
result_of<F(T1, T2, ...,
+ TN)>::type
names the type
+ decltype(boost::declval<F>()(boost::declval<T1>(),
+ boost::declval<T2>(), ...,
+ boost::declval<TN>())), as in the
+ following example.
- #include <boost/utility/result_of.hpp>
-
-struct functor {
+ struct functor {
template<class T>
T operator()(T x)
{
@@ -249,7 +253,7 @@ typedef boost::result_of<
result_type
and
result<>
members accurately
represent the return type of
- operator()
.
+ operator()
given a call expression.
This implementation of result_of
@@ -266,6 +270,321 @@ typedef boost::result_of<
N1836,
or, for motivation and design rationale,
the result_of
proposal.
+
+
+ Usage guidelines for boost::result_of
+
+
+ The following are general suggestions about when
+ and how to use boost::result_of
.
+
+
+ - If you are targeting C++11 and are not concerned
+ about portability to non-compliant compilers or
+ previous versions of the standard, then use
+
std::result_of
. If std::result_of
+ meets your needs, then there's no reason to stop using
+ it.
+
+ - If you are targeting C++11 but may port your code
+ to legacy compilers at some time in the future, then
+ use
boost::result_of
with
+ decltype
. When decltype
is
+ used boost::result_of
+ and std::result_of
are usually
+ interchangeable. See the documentation on
+ known differences
+ between boost::result_of and C++11 result_of.
+
+ - If compiler portability is required,
+ use
boost::result_of
with the TR1 protocol.
+
+
+ Regardless of how you
+ configure boost::result_of
, 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. boost::result_of
must be passed
+ the appropriately cv-qualified types in order to
+ deduce the corresponding return type. For example:
+
+
+ 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 &
+
+
+
+ Usage guidelines for the TR1 result_of protocol
+
+
+ On compliant C++11
+ compilers, boost::result_of
can
+ use decltype
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.
+
+
+ - When the return type does not depend on the
+ argument types or the cv-qualification of the
+ function object, simply
+ define
result_type
. There is no need
+ to use the result
template unless the
+ return type varies.
+
+ - 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:
+
+
+ struct functor {
+ typedef int result_type;
+ result_type operator()(int);
+};
+
+
+ - Always specify the
result
+ specialization near the corresponding
+ operator()
overload. This can make it
+ easier to keep the specializations in sync with the
+ overloads. For example:
+
+
+ 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;
+};
+
+
+ - Use type transformations to simplify
+ the
result
template specialization. For
+ example, the following uses
+ Boost.TypeTraits
+ to specialize the result
template for
+ a single operator()
that can be called on
+ both a const and non-const function object with
+ either an lvalue or rvalue argument.
+
+
+ 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;
+};
+
+
+
+
+ Known differences between boost::result_of and TR1 result_of
+
+
+ When using decltype
, boost::result_of
+ ignores the TR1 protocol and instead deduces the
+ return type of function objects directly
+ via decltype
. 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 boost::result_of
is known to differ depending on
+ whether decltype
or the TR1 protocol is
+ used.
+
+
+ - TR1 protocol misusage
+
+
When using the TR1
+ protocol, boost::result_of
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 decltype
, these subtle bugs
+ may result in compilation errors. For example:
+
+
+ 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
+
+
+ Note that the user can
+ force boost::result_of
to use the TR1
+ protocol even on platforms that
+ support decltype
by
+ defining BOOST_RESULT_OF_USE_TR1
.
+
+ - Nullary function objects
+
+
When using the TR1 protocol, boost::result_of
+ cannot always deduce the type of calls to
+ nullary function objects, in which case the
+ type defaults to void. When using decltype
,
+ boost::result_of
always gives the actual type of the
+ call expression. For example:
+
+
+ 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
+
+
+ Note that there are some workarounds for the
+ nullary function problem. So long as the return
+ type does not vary,
+ result_type
can always be used to
+ specify the return type regardless of arity. If the
+ return type does vary, then the user can
+ specialize boost::result_of
itself for
+ nullary calls.
+
+ - Non-class prvalues and cv-qualification
+
+
When using the TR1
+ protocol, boost::result_of
will
+ report the cv-qualified type specified
+ by result_type
or
+ the result
template regardless of
+ the actual cv-qualification of the call
+ expression. When using
+ decltype
, boost::result_of
+ will report the actual type of the call expression,
+ which is not cv-qualified when the expression is a
+ non-class prvalue. For example:
+
+
+ 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
+
+
+
+
+ Known differences between boost::result_of and C++11 result_of
+
+
+ When using decltype
, boost::result_of
+ implements most of the C++11 result_of
+ specification. One known exception is that
+ boost::result_of
does not implement the
+ requirements regarding pointers to member data.
+
Created by Doug Gregor. Contributions from Daniel Walker, Eric Niebler, Michel Morin and others
Class templates for the Base-from-Member Idiom