422 lines
14 KiB
Plaintext
Executable File
422 lines
14 KiB
Plaintext
Executable File
[/
|
|
/ 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& 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]
|