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.

### 891. `std::thread`, `std::call_once` issue

Section: 33.4.3.3 [thread.thread.constr], 33.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 33.4.3.3 [thread.thread.constr] and 33.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 values `w1, 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 for this, for the formulation on how to solve this. 929 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 for `call_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 33.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 parameters `Callable` and each `Ti` in `Args` shall be `CopyConstructible` if an lvalue and otherwise satisfy the `MoveConstructible` requirements. `INVOKE(decay_copy(std::forward<Callable>(func), w1, w2, ..., wN decay_copy(std::forward<Args>(args))...)` (22.10.4 [func.require]) shall be a valid expression for some values `w1, w2, ..., wN`, where `N == sizeof...(Args)`.

> > 2 Effects: Calls to `call_once` on the same `once_flag` object are serialized. If there has been a prior effective call to `call_once` on the same `once_flag` object, the call to `call_once` returns without invoking `func`. If there has been no prior effective call to `call_once` on the same `once_flag` object, the argument `func` (or a copy thereof) is called as if by invoking `func(args)` `INVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...)` is executed. The call to `call_once` is effective if and only if `func(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.