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.
Section: 22.10.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.
- bind needs to be "moved".
- 22.10.15.4 [func.bind.bind]/p3, p6 and p7 were accidently removed from N2798.
- 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 22.10 [function.objects] p2:
template<class Fn, class...TypesBoundArgs> unspecified bind(Fn&&,TypesBoundArgs&&...); template<class R, class Fn, class...TypesBoundArgs> unspecified bind(Fn&&,TypesBoundArgs&&...);
Change 22.10.4 [func.require]:
4 Every call wrapper (22.10.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 formtemplate<class...ArgTypesUnBoundsArgs> R operator()(ArgTypesUnBoundsArgs&&... unbound_args) cv-qual;— end note]
Change 22.10.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) (22.10.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 (22.10.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
copyconstructionorofFfd or of one of the values tidtypes in the BoundArgs... pack expansionthrows 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
copyconstructionorofFfd or of one of the values tidtypes in the BoundArgs... pack expansionthrows 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 inthe call to bind and the cv-qualifiers cv of the call wrapper g as follows:
- if
tiTiD isof typereference_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 &.