| Home | Libraries | People | FAQ | More

### Result of

#### Introduction

The class template `result_of` helps determine the type of a call expression. For example, given an lvalue `f` of type `F` and lvalues `t1`,`t2`, ..., `tN` of types `T1`, `T2`, ..., `TN`, respectively, the type `result_of``<F(T1, T2, ..., TN)>::type` defines the result type of the expression `f(t1, t2, ...,tN)`.

This implementation permits the type `F` to be a function pointer, function reference, member function pointer, or class type. By default, N may be any value between 0 and 16. To change the upper limit, define the macro `BOOST_RESULT_OF_NUM_ARGS` to the maximum value for N. Class template `result_of` resides in the header `<boost/utility/result_of.hpp>`.

If your compiler's support for `decltype` is adequate, `result_of` automatically uses it to 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.

    struct functor {
        template<class T>
        T operator()(T x)
        {
            return x;
        }
    };

    typedef boost::result_of<functor(int)>::type type; // type is int

You can test whether `result_of` is using `decltype` by checking if the macro `BOOST_RESULT_OF_USE_DECLTYPE` is defined after including `result_of.hpp`. You can also force `result_of` to use `decltype` by defining `BOOST_RESULT_OF_USE_DECLTYPE` prior to including `result_of.hpp`.

If `decltype` is not used, then automatic result type deduction of function objects is not possible. Instead, `result_of` uses the following protocol to allow the programmer to specify a type. When `F` is a class type with a member type `result_type`, `result_of<F(T1, T2, ..., TN)>::type` is `F::result_type`. When `F` does not contain `result_type`, `result_of<F(T1, T2, ..., TN)>::type` is `F::result<F(T1, T2, ..., TN)>::type` when `N > 0` or `void` when `N = 0`.

Note that it is the responsibility of the programmer to ensure that function objects accurately advertise their result type via this protocol, as in the following example.

    struct functor {
        template <class> struct result;

        template<class F, class T>
        struct result<F(T)> {
            typedef T type;
        };

        template<class T>
        T operator()(T x)
        {
            return x;
        }
    };

    typedef boost::result_of<functor(int)>::type type; // type is int

Since `decltype` is a language feature standardized in C++11, if you are writing a function object to be used with `result_of`, for maximum portability, you might consider following the above protocol even if your compiler has proper `decltype` support.

If you wish to continue to use the protocol on compilers that support `decltype`, there are two options:

- You can use `boost::tr1_result_of`, which is also defined in `<boost/utility/result_of.hpp>`.
- Alternatively, you can define the macro `BOOST_RESULT_OF_USE_TR1`, which causes `result_of` to use the protocol described above instead of `decltype`. If you choose to follow the protocol, take care to ensure that the `result_type` and `result<>` members accurately represent the return type of `operator()` given a call expression.

Additionally, `boost::result_of` provides a third mode of operation, which some users may find convenient. When `BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK` is defined, `boost::result_of` behaves as follows. If the function object has a member type `result_type` or member template `result<>`, then `boost::result_of` will use the TR1 protocol.

Otherwise, `boost::result_of` will use `decltype`. Using TR1 with a `decltype` fallback may workaround certain problems at the cost of portability. For example:

- Deficient compiler: If your code requires `boost::result_of` to work with incomplete return types but your compiler's `decltype` implementation does not support incomplete return types, then you can use the TR1 protocol as a workaround. Support for incomplete return types was added late in the C++11 standardization process (see N3276) and is not implemented by some compilers.
- Deficient legacy code: If your existing TR1 function object advertises a different type than the actual result type deduced by `decltype`, then using TR1 with a `decltype` fallback will allow you to work with both your existing TR1 function objects and new C++11 function object. This situation could occur if your legacy function objects misused the TR1 protocol. See the documentation on known differences between `boost::result_of` and TR1.
- This implementation of `result_of` requires class template partial specialization, the ability to parse function types properly, and support for SFINAE. If `result_of` is not supported by your compiler, including the header `<boost/utility/result_of.hpp>` will define the macro `BOOST_NO_RESULT_OF`.

For additional information about `result_of`, see the C++ Library Technical Report, 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. 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 `std::result_of`.
3. 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.</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:

    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&amp; x) const;
    };

#### Known differences between `boost::result_of` and `boost::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 `std::result_of` specification. One known exception is that `boost::result_of` does not implement the requirements regarding pointers to member data.

#### Reference

##### Header <boost/utility/result_of.hpp>

    namespace boost {
      template<typename F> struct result_of;
      template<typename F> struct tr1_result_of;
    }

#### Acknowledgments

Created by Doug Gregor. Contributions from Daniel Walker, Eric Niebler, Michel Morin and others.