This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
2021. Further incorrect usages ofresult_of
Section: 22.10.15.4 [func.bind.bind], 32.10.1 [futures.overview], 32.10.9 [futures.async] Status: C++14 Submitter: Daniel Krügler Opened: 2010-12-07 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [func.bind.bind].
View all issues with C++14 status.
Discussion:
Issue 2017(i) points out some incorrect usages of result_of
in the declaration of the function call operator overload of reference_wrapper
, but there are more such specification defects:
[..] The effect of
g(u1, u2, ..., uM)
shall beINVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type)
[..]
but fd
is defined as "an lvalue of type FD
constructed from std::forward<F>(f)
". This means that the above usage must refer to result_of<FD cv & (V1, V2, ..., VN)>
instead.
Similar in 22.10.15.4 [func.bind.bind] p. 10 bullet 2 we have:
if the value of
is_bind_expression<TiD>::value
is true, the argument istid(std::forward<Uj>(uj)...)
and its typeVi
isresult_of<TiD cv (Uj...)>::type
Again, tid
is defined as "lvalue of type TiD
constructed from std::forward<Ti>(ti)
". This means that the above usage must refer to result_of<TiD cv & (Uj...)>
instead. We also have similar defect as in 2017(i) in regard to the argument types, this leads us to the further corrected form result_of<TiD cv & (Uj&&...)>
. This is not the end: Since the Vi
are similar sensitive to the argument problem, the last part must say:
Vi
is result_of<TiD cv & (Uj&&...)>::type &&"
(The bound arguments Vi
can never be void
types, therefore we don't need to use the more defensive std::add_rvalue_reference
type trait)The function template async
is declared as follows (the other overload has the same problem):
template <class F, class... Args> future<typename result_of<F(Args...)>::type> async(F&& f, Args&&... args);
This usage has the some same problems as we have found in reference_wrapper
(2017(i)) and more: According to the specification in 32.10.9 [futures.async] the effective result type is that of the call of
INVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
First, decay_copy
potentially modifies the effective types to decay<F>::type
and decay<Args>::type...
. Second, the current specification is not really clear, what the value category of callable type or the arguments shall be: According to the second bullet of 32.10.9 [futures.async] p. 3:
Invocation of the deferred function evaluates
INVOKE(g, xyz)
whereg
is the stored value ofdecay_copy(std::forward<F>(f))
andxyz
is the stored copy ofdecay_copy(std::forward<Args>(args))...
.
This seems to imply that lvalues are provided in contrast to the direct call expression of 32.10.9 [futures.async] p. 2 which implies rvalues instead. The specification needs to be clarified.
[2011-06-13: Daniel comments and refines the proposed wording changes]
The feedback obtained following message c++std-lib-30745 and follow-ups point to the intention, that the implied provision of lvalues due to named variables in async
should be provided as rvalues to support move-only types, but the functor type should be forwarded as lvalue in bind
.
bind
were newly invented, the value strategy could be improved, because now we have a preference of ref &
qualified function call operator overloads. But such a change seems to be too late now. User-code that needs to bind a callable object with an ref &&
qualified function call operator (or conversion function to function pointer) needs to use a corresponding wrapper similar to reference_wrapper
that forwards the reference as rvalue-reference instead. The wording has been adapted to honor these observations and to fit to FDIS numbering as well.
[Bloomington, 2011]
Move to Ready
Proposed resolution:
The suggested wording changes are against the FDIS.
Change 22.10.15.4 [func.bind.bind] p. 3 as indicated:
template<class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-2- Requires:
-3- Returns: A forwarding call wrapperis_constructible<FD, F>::value
shall be true. For eachTi
inBoundArgs
,is_constructible<TiD, Ti>::value
shall be true.INVOKE(fd, w1, w2, ..., wN)
(20.8.2) shall be a valid expression for some valuesw1
,w2
, ...,wN
, whereN == sizeof...(bound_args)
.g
with a weak result type (20.8.2). The effect ofg(u1, u2, ..., uM)
shall beINVOKE(fd, std::forward<V1>(v1 ), std::forward<V2>(v2 ), ..., std::forward<VN>(vN ), result_of<FD cv & (V1, V2, ..., VN)>::type)
, where cv represents the cv-qualifiers ofg
and the values and types of the bound argumentsv1
,v2
, ...,vN
are determined as specified below. […]
Change 22.10.15.4 [func.bind.bind] p. 7 as indicated:
template<class R, class F, class... BoundArgs> unspecified bind(F&& f, BoundArgs&&... bound_args);-6- Requires:
-7- Returns: A forwarding call wrapperis_constructible<FD, F>::value
shall be true. For eachTi
inBoundArgs
,is_constructible<TiD, Ti>::value
shall be true.INVOKE(fd, w1, w2, ..., wN)
shall be a valid expression for some valuesw1
,w2
, ...,wN
, whereN == sizeof...(bound_args)
.g
with a nested typeresult_type
defined as a synonym forR
. The effect ofg(u1, u2, ..., uM)
shall beINVOKE(fd, std::forward<V1>(v1 ), std::forward<V2>(v2 ), ..., std::forward<VN>(vN ), R)
, where the values and types of the bound argumentsv1
,v2
, ...,vN
are determined as specified below. […]
Change 22.10.15.4 [func.bind.bind] p. 10 as indicated:
-10- The values of the bound arguments
v1
,v2
, ...,vN
and their corresponding typesV1
,V2
, ...,VN
depend on the typesTiD
derived from the call to bind and the cv-qualifiers cv of the call wrapperg
as follows:
- if
TiD
isreference_wrapper<T>
, the argument istid.get()
and its typeVi
isT&
;- if the value of
is_bind_expression<TiD>::value
istrue
, the argument istid(std::forward<Uj>(uj)...)
and its typeVi
isresult_of<TiD cv & (Uj &&...)>::type &&
;- if the value
j
ofis_placeholder<TiD>::value
is not zero, the argument isstd::forward<Uj>(uj)
and its typeVi
isUj&&
;- otherwise, the value is
tid
and its typeVi
isTiD cv &
.
This resolution assumes that the wording of 32.10.9 [futures.async] is intended to provide rvalues as arguments of INVOKE
.
Change the function signatures in header <future>
synopsis 32.10.1 [futures.overview] p. 1 and in 32.10.9 [futures.async] p. 1 as indicated:
template <class F, class... Args> future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type> async(F&& f, Args&&... args); template <class F, class... Args> future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type> async(launch policy, F&& f, Args&&... args);
Change 32.10.9 [futures.async] as indicated: (Remark: There is also a tiny editorial correction in p. 4 that completes one ::
scope specifier)
-3- Effects: […]
- […]
- if
policy & launch::deferred
is non-zero — StoresDECAY_COPY(std::forward<F>(f))
andDECAY_COPY(std::forward<Args>(args))...
in the shared state. These copies off
andargs
constitute a deferred function. Invocation of the deferred function evaluatesINVOKE( std::move(g ), std::move(xyz ))
whereg
is the stored value ofDECAY_COPY(std::forward<F>(f))
andxyz
is the stored copy ofDECAY_COPY(std::forward<Args>(args))...
. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function (30.6.4) on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation ofINVOKE( std::move(g ), std::move(xyz ))
begins, the function is no longer considered deferred. [ Note: If this policy is specified together with other policies, such as when using apolicy
value oflaunch::async | launch::deferred
, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited. — end note ]
-4- Returns: an object of type
future<typename result_of< typename decay<F >::type( typename decay<Args >::type...)>: :type>
that refers to the associated asynchronous state created by this call toasync
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4