This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2545. Simplify wording for `bind` without explicitly specified return type

Section: 20.14.15.4 [func.bind.bind] Status: C++17 Submitter: Tomasz Kamiński Opened: 2015-10-05 Last modified: 2017-07-30

Priority: 3

View all other issues in [func.bind.bind].

View all issues with C++17 status.

Discussion:

The specification of the `bind` overload without return type as of 20.14.15.4 [func.bind.bind] p3, uses the following expression `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ..., VN)>)` to describe effects of invocation of returned function.

According to the definition from 20.15.8.7 [meta.trans.other] `result_of_t<FD cv & (V1, V2, ..., VN)>` is equivalent to `decltype(INVOKE(declval<FD cv &>(), declval<V1>(), declval<V2>(), ..., declval<VN>()))`. When combined with the definition of `INVOKE` from 20.14.4 [func.require] p2, the expression `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ...., VN)>)` is equivalent to `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))` implicitly converted to `decltype(INVOKE(declval<FD cv &>(), declval<V1>(), declval<V2>(), ..., declval<VN>()))` (itself).

It is also worth to notice that specifying the result type (`R`) in `INVOKE(f, args..., R)` does not in any way affect the selected call. As a consequence the use of wording of the form `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ..., VN)>)` does not and cannot lead to call of different overload than one invoked by `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))`.

In summary the form `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ..., VN)>)` is a convoluted way of expressing `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))`, that only confuses reader.

[2015-10, Kona Saturday afternoon]

STL: I most recently reimplemented std::bind from scratch, and I think this issue is correct and the solution is good.

Move to Tentatively ready.

Proposed resolution:

This wording is relative to N4527.

1. Change 20.14.15.4 [func.bind.bind] p3 as indicated:

   >     template<class F, class... BoundArgs>
   >     unspecified bind(F&& f, BoundArgs&&... bound_args);

   > > […]

   > > -3- Returns: A forwarding call wrapper `g` with a weak result type (20.9.2). The effect of `g(u1, u2, ..., uM)` shall be `INVOKE(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN), result_of_t<FD cv & (V1, V2, ..., VN)>)`, where `cv` represents the cv-qualifiers of `g` and the values and types of the bound arguments `v1, v2, ..., vN` are determined as specified below. The copy constructor and move constructor of the forwarding call wrapper shall throw an exception if and only if the corresponding constructor of `FD` or of any of the types `TiD` throws an exception.

   > > […]