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

### 817. `bind` needs to be moved

Section: 20.14.15.4 [func.bind.bind] Status: C++11 Submitter: Howard Hinnant Opened: 2008-03-17 Last modified: 2016-01-28

Priority: Not Prioritized

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

View all issues with C++11 status.

Discussion:

Addresses US 72, JP 38 and DE 21

The functor returned by `bind()` should have a move constructor that requires only move construction of its contained functor and bound arguments. That way move-only functors can be passed to objects such as `thread`.

This issue is related to issue 816.

US 72:

> `bind` should support move-only functors and bound arguments.

JP 38:

> add the move requirement for bind's return type.

> For example, assume following `th1` and `th2`,

> >     void f(vector<int> v) { }

> >     vector<int> v{ ... };
> >     thread th1([v]{ f(v); });
> >     thread th2(bind(f, v));

> When function object are set to thread, `v` is moved to `th1`'s lambda expression in a Move Constructor of lambda expression because `th1`'s lambda expression has a Move Constructor. But `bind` of `th2`'s return type doesn't have the requirement of Move, so it may not moved but copied.

> Add the requirement of move to get rid of this useless copy.

> And also, add the `MoveConstructible` as well as `CopyConstructible`.

DE 21

> The specification for bind claims twice that "the values and types for the bound arguments v1, v2, ..., vN are determined as specified below". No such specification appears to exist.

[ San Francisco: ]

> Howard to provide wording.

[ Post Summit Alisdair and Howard provided wording. ]

> Several issues are being combined in this resolution. They are all touching the same words so this is an attempt to keep one issue from stepping on another, and a place to see the complete solution in one place.

> 1. `bind` needs to be "moved".
> 2. 20.14.15.4 [func.bind.bind]/p3, p6 and p7 were accidently removed from N2798.
> 3. Issue 929 argues for a way to pass by && for efficiency but retain the decaying behavior of pass by value for the `thread` constructor. That same solution is applicable here.

[ Batavia (2009-05): ]

> We were going to recommend moving this issue to Tentatively Ready until we noticed potential overlap with issue 816 (q.v.).

> Move to Open, and recommend both issues be considered together (and possibly merged).

[ 2009-07 Frankfurt: ]

> The proposed resolution uses concepts. Leave Open.

[ 2009-10 Santa Cruz: ]

> Leave as Open. Howard to provide deconceptified wording.

[ 2009-11-07 Howard updates wording. ]

[ 2009-11-15 Further updates by Peter, Chris and Daniel. ]

[ Moved to Tentatively Ready after 6 positive votes on c++std-lib. ]

Proposed resolution:

Change 20.14 [function.objects] p2:

>     template<class Fn, class... Types BoundArgs>
>       unspecified bind(Fn&&, Types BoundArgs&&...);
>     template<class R, class Fn, class... Types BoundArgs>
>       unspecified bind(Fn&&, Types BoundArgs&&...);

Change 20.14.4 [func.require]:

> 4 Every call wrapper (20.14.3 [func.def]) shall be `CopyMoveConstructible`. A simple call wrapper is a call wrapper that is `CopyConstructible` and `CopyAssignable` and whose copy constructor, move constructor and assignment operator do not throw exceptions. A forwarding call wrapper is a call wrapper that can be called with an argument list. [Note: in a typical implementation forwarding call wrappers have an overloaded function call operator of the form

> >     template<class... ArgTypesUnBoundsArgs>
> >     R operator()(ArgTypesUnBoundsArgs&&... unbound_args) cv-qual;

> — end note]

Change 20.14.15.4 [func.bind.bind]:

> Within this clause:

> - Let `FD` be a synonym for the type `decay<F>::type`.
> - Let `fd` be an lvalue of type `FD` constructed from `std::forward<F>(f)`.
> - Let `Ti` be a synonym for the ith type in the template parameter pack `BoundArgs`.
> - Let `TiD` be a synonym for the type `decay<Ti>::type`.
> - Let `ti` be the ith argument in the function parameter pack `bound_args`.
> - Let `tid` be an lvalue of type `TiD` constructed from `std::forward<Ti>(ti)`.
> - Let `Uj` be the jth deduced type of the `UnBoundArgs&&...` parameter of the `operator()` of the forwarding call wrapper.
> - Let `uj` be the jth argument associated with `Uj`.

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

> > -1- Requires: `is_constructible<FD, F>::value` shall be `true`. For each `Ti` in `BoundArgs`, `is_constructible<TiD, Ti>::value` shall be `true`. `F` and each `Ti` in `BoundArgs` shall be CopyConstructible. `INVOKE(fd, w1, w2, ..., wN)` (20.14.4 [func.require]) shall be a valid expression for some values w1, w2, ..., wN, where `N == sizeof...(bound_args)`.

> > -2- Returns: A forwarding call wrapper `g` with a weak result type (20.14.4 [func.require]). The effect of `g(u1, u2, ..., uM)` shall be `INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type)`, 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.

> > -3- Throws: Nothing unless the copy construction or of `Ffd` or of one of the values `tid` types in the `BoundArgs...` pack expansion throws an exception.

> > Remarks: The unspecified return type shall satisfy the requirements of `MoveConstructible`. If all of `FD` and `TiD` satisfy the requirements of `CopyConstructible` then the unspecified return type shall satisfy the requirements of `CopyConstructible`. [Note: This implies that all of `FD` and `TiD` shall be `MoveConstructible` — end note]

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

> > -4- Requires: `is_constructible<FD, F>::value` shall be `true`. For each `Ti` in `BoundArgs`, `is_constructible<TiD, Ti>::value` shall be `true`. `F` and each `Ti` in `BoundArgs` shall be CopyConstructible. `INVOKE(fd, w1, w2, ..., wN)` shall be a valid expression for some values w1, w2, ..., wN, where `N == sizeof...(bound_args)`.

> > -5- Returns: A forwarding call wrapper `g` with a nested type `result_type` defined as a synonym for `R`. The effect of `g(u1, u2, ..., uM)` shall be `INVOKE(fd, v1, v2, ..., vN, R)`, where 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.

> > -6- Throws: Nothing unless the copy construction or of `Ffd` or of one of the values `tid` types in the `BoundArgs...` pack expansion throws an exception.

> > Remarks: The unspecified return type shall satisfy the requirements of `MoveConstructible`. If all of `FD` and `TiD` satisfy the requirements of `CopyConstructible` then the unspecified return type shall satisfy the requirements of `CopyConstructible`. [Note: This implies that all of `FD` and `TiD` shall be `MoveConstructible` — end note]

> -7- The values of the bound arguments `v1, v2, ..., vN` and their corresponding types `V1, V2, ..., VN` depend on the types `TiD` derived from of the corresponding argument `ti` in `bound_args` of type `Ti` in `BoundArgs` in the call to `bind` and the cv-qualifiers cv of the call wrapper `g` as follows:

> - if `ti TiD` is of type `reference_wrapper<T>` the argument is `tid.get()` and its type `Vi` is `T&`;
> - if the value of `std::is_bind_expression<TiD>::value` is `true` the argument is `tid(std::forward<Uj>(uj)... u1, u2, ..., uM)` and its type `Vi` is `result_of<TiD cv (Uj... U1&, U2&, ..., UM&)>::type`;
> - if the value `j` of `std::is_placeholder<TiD>::value` is not zero the argument is `std::forward<Uj>(uj)` and its type `Vi` is `Uj&&`;
> - otherwise the value is `tid` and its type `Vi` is `TiD cv &`.