[/ / 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__`::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__`::type` names the type __decltype__`(boost::declval()(boost::declval(), boost::declval(), ..., boost::declval()))`, as in the following example. ``` struct functor { template T operator()(T x) { return x; } }; typedef __boost_result_of__::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::type` is `F::result_type`. When `F` does not contain `result_type`, `result_of::type` is `F::result::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 struct result; template struct result { typedef T type; }; template T operator()(T x) { return x; } }; typedef __boost_result_of__::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 [@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 ``] 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. * 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 struct result; template struct result { typedef int& type; }; result::type operator()(int); template struct result { typedef int const& type; }; result::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 struct result; template struct result : boost::remove_cv< typename boost::remove_reference::type > {}; template 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__::type, int>::value )); #else BOOST_STATIC_ASSERT(( boost::is_same<__boost_result_of__::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 struct result { typedef int type; }; int operator()(); }; #ifdef BOOST_RESULT_OF_USE_DECLTYPE BOOST_STATIC_ASSERT(( boost::is_same<__boost_result_of__::type, int>::value )); #else BOOST_STATIC_ASSERT(( boost::is_same<__boost_result_of__::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 struct result; template struct result { 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__::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__::type, short ::value )); #else BOOST_STATIC_ASSERT(( boost::is_same< __boost_result_of__::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]