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: 22.10.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 22.10.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 21.3.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 22.10.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 22.10.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.

    […]