diff --git a/utility.htm b/utility.htm index 73bd692..c46c515 100644 --- a/utility.htm +++ b/utility.htm @@ -143,7 +143,7 @@ void f() {

Class template result_of

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.

+ deduce the type of the call expression, in which case + 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.

+ +
    +
  1. 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.
  2. + +
  3. 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.
  4. + +
  5. If compiler portability is required, + use boost::result_of with the TR1 protocol.
  6. +
+ +

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