[/
 / Copyright (c) 2012 Marshall Clow
 / Copyright (c) 2021, Alan Freitas
 /
 / Distributed under the Boost Software License, Version 1.0. (See accompanying
 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 /]

[/===============]
[section Result of]
[/===============]

[section 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 `<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 `<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 [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf 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 [link sec:result_of_tr1_diff differences]
between __boost_result_of__ and TR1.

* [#BOOST_NO_RESULT_OF] 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 `<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, [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf N1836],
or, for motivation and design rationale, the __result_of__
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1454.html proposal].

[endsect]

[#sec:result_of_guidelines]
[section 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 [link sec:result_of_cxx11_diff differences]
between __boost_result_of__ and C++11 __std_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 &
```

[endsect]

[#sec:result_of_tr1_protocol_guidelines]
[section 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 [@../type_traits/doc/html/index.html 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;
};
```

[endsect]

[#sec:result_of_tr1_diff]
[section 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
```

[endsect]

[#sec:result_of_cxx11_diff]
[section 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.

[endsect]

[/===============]
[xinclude tmp/result_of_reference.xml]
[/===============]

[section Acknowledgments]

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

[endsect]

[endsect]