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.
std::thread
, std::call_once
issueSection: 32.4.3.3 [thread.thread.constr], 32.6.7.2 [thread.once.callonce] Status: C++11 Submitter: Peter Dimov Opened: 2008-09-15 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [thread.thread.constr].
View all issues with C++11 status.
Discussion:
I notice that the vararg overloads of std::thread
and std::call_once
(N2723 32.4.3.3 [thread.thread.constr] and 32.6.7.2 [thread.once.callonce]) are no longer specified in terms of
std::bind
; instead, some of the std::bind
wording has been inlined into
the specification.
There are two problems with this.
First, the specification (and implementation) in terms of std::bind
allows, for example:
std::thread th( f, 1, std::bind( g ) );
which executes f( 1, g() )
in a thread. This can be useful. The
"inlined" formulation changes it to execute f( 1, bind(g) )
in a thread.
Second, assuming that we don't want the above, the specification has copied the wording
INVOKE(func, w1, w2, ..., wN)
(20.6.2) shall be a valid expression for some valuesw1, w2, ..., wN
but this is not needed since we know that our argument list is args; it should simply be
INVOKE(func, args...)
(20.6.2) shall be a valid expression
[ Summit: ]
Move to open.
[ Post Summit Anthony provided proposed wording. ]
[ 2009-07 Frankfurt ]
Leave Open. Await decision for thread variadic constructor.
[ 2009-10 Santa Cruz: ]
See proposed wording for 929(i) for this, for the formulation on how to solve this. 929(i) modifies the thread constructor to have "pass by value" behavior with pass by reference efficiency through the use of the
decay
trait. This same formula would be useful forcall_once
.
[ 2010-02-11 Anthony updates wording. ]
[ 2010-02-12 Moved to Tentatively Ready after 5 postive votes on c++std-lib. ]
Proposed resolution:
Modify 32.6.7.2 [thread.once.callonce] p1-p2 with the following:
template<class Callable, class ...Args> void call_once(once_flag& flag, Callable&& func, Args&&... args);Given a function as follows:
template<typename T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }1 Requires:
The template parametersCallable
and eachTi
inArgs
shallbesatisfy theCopyConstructible
if an lvalue and otherwiseMoveConstructible
requirements.INVOKE(decay_copy(std::forward<Callable>(func),
(22.10.4 [func.require]) shall be a valid expressionw1, w2, ..., wNdecay_copy(std::forward<Args>(args))...)for some values.w1, w2, ..., wN
, whereN == sizeof...(Args)
2 Effects: Calls to
call_once
on the sameonce_flag
object are serialized. If there has been a prior effective call tocall_once
on the sameonce_flag
object, the call tocall_once
returns without invokingfunc
. If there has been no prior effective call tocall_once
on the sameonce_flag
object,the argumentfunc
(or a copy thereof) is called as if by invokingfunc(args)
INVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...)
is executed. The call tocall_once
is effective if and only iffunc(args)
INVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...)
returns without throwing an exception. If an exception is thrown it is propagated to the caller.