BDE 4.14.0 Production release
|
Determine the result type of an invocable expression.
bsl::invoke_result
This component provides a metafunction bsl::invoke_result
that determines, at compile time, the type returned by invoking a callable type, including pointer-to-function, pointer-to-member function, pointer-to-member object (returns the object type), or functor class and a class bslmf::InvokeResultDeductionFailed
that is returned when the invocation return type cannot be determined (C++03 only). For a set of types F
, T1
, T2
, and T3
, bsl::invoke_result<F, T1, t2, T3>::type
is roughly the type of the return value obtained by calling an object of type F
with arguments of type T1
, T2
, and T3
, respectively. However, invoke_result goes beyond function-like objects and deduces a return type if F
is a pointer to function member or data member of some class C
and T1
is a type (derived from) C
, pointer to C
, or smart-pointer to C
. (See precise specification, below). For the convenience of users, an alias for the type returned by the bsl::invoke_result
, bsl::invoke_result_t
, is provided by this component.
The interfaces and functionality of bsl::invoke_result
and bsl::invoke_result_t
are intended to be identical to that of the C++17 metafunctions, std::invoke_result
and std::invoke_result_t
except that invalid argument lists are detected in C++11 and later, but not in C++03. In C++03, invalid arguments lists will result in a compilation error (instead of simply missing type
) in the remaining cases. Some other functionality is lost when compiling with a C++03 compiler – see the precise specification, below.
This component defines the macro BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS
if bsl::invoke_result
behaves according to the C++17 specification of std::invoke_result
, which is elaborated below. This macro is defined as long as the compiler supports the decltype
specifier, which is generally available in C++11 and later compilation modes.
The C++11 and C++14 standard defines the pseudo-expression INVOKE (f, t1, t2, ..., tN)
, as follows:
(t1.*f)(t2, ..., tN)
when f
is a pointer to a member function of a class T
and t1
is an object of type T
or a reference to an object of type T
or a reference to an object of a type derived from T
;((*t1).*f)(t2, ..., tN)
when f
is a pointer to a member function of a class T
and t1
is not one of the types described in the previous item;t1.*f
when N == 1
and f
is a pointer to member data of a class T
and t1
is an object of type T
or a reference to an object of type T
or a reference to an object of a type derived from T
;(*t1).*f
when N == 1
and f
is a pointer to member data of a class T
and t1
is not one of the types described in the previous item;f(t1, t2, ..., tN)
in all other cases.Given types F
, T1
, T2
, ..., TN
corresponding to the expressions f
, t1
, t2
, ..., tN
in the definition of INVOKE, the type produced by bslmf::ResultType<F, T1, T2, ..., TN>::type
is generally the type of the psuedo-expression INVOKE (f, t1, t2, ..., tN)
, with some limitations in C++03, as described below.
Because C++03 does not support decltype
, there are circumstances in which bsl::invoke_result
is not able to deduce the return type of an invocable object of class type (i.e., a functor). If R
is the type of the INVOKE expression, then ideally type
is R
. However the C++03 version of bsl::invoke_result
determines type
as follows:
bsl::invoke_result<F, T1, T2, ... TN>
, then type
is determined by the specialization, regardless of correctness. (This rule is true of C++11 and later, as well.)F
is a function type, pointer to function type, pointer to member function type, pointer to member object type, or reference to any of these (i.e, F
is anything other than a class type or reference to class type), then type
is R
.R
is o a fundamental type, o a pointer to (possibly cv-qualified) void
or fundamental type, o an lvalue reference to any of the above types (possibly cv-qualified), o bsl::nullptr_t
, or o void
, then type
is R
.F
is a class type with member result_type
, then type
is F::result_type
. Note that bsl::invoke_result
cannot deduce different result types for different overloads of operator()
in this case.F
is a class type with member type ResultType
, then type
is F::ResultType
. Note that bsl::invoke_result
cannot deduce different result types for different overloads of operator()
in this case.type
is bslmf::InvokeResultDeductionFailed
. The benefit of this placeholder over a compilation error is that invoke_result is often used in a context where the return value will eventually be discarded. Thus, generating a useless type is often harmless. In cases where it is not harmless, the placeholder type will almost certainly result in a compilation error in the surrounding code.If the callable type is a pointer-to-member (data or function), invalid argument lists are not detected. Thus, there is a small chance that invalid code will compile successfully, though it is hard to see now this would be harmful, since determining the return type of an expression is not very useful if the expression is not eventually evaluated, which will certainly produce the expected compilation error for invalid argument lists.
Suppose we want to create a wrapper that executes an invocable object and sets a done
flag. The done
flag will not be set if the invocation exits via an exception. The wrapper takes an invocable f
and an argument x
and evaluates f(x)
, returning the result. In the absence of C++14 automatically-deduced function return declarations, we use bsl::invoke_result
to deduce the return type of f(x)
.
First, we write the wrapper template as follows:
Note that additional metaprogramming would be required to make this template work for return type void
; such metaprogramming is beyond the scope of this usage example.
Then we define a couple of simple functors to be used with the wrapper. The first functor is a simple template that triples its invocation argument:
Next, we define a second functor that returns an enumerator ODD
or EVEN
, depending on whether its argument is exactly divisible by 2. Since the return type is not a fundamental type, this functor indicates its return type using the ResultType
idiom:
Finally, we can invoke these functors through our wrapper: