packaged_task
constructors should be constrainedSection: 32.10.10.2 [futures.task.members] Status: C++14 Submitter: Jonathan Wakely Opened: 2011-11-02 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with C++14 status.
Discussion:
With the proposed resolution of 2067, this no longer selects the copy constructor:
std::packaged_task<void()> p1; std::packaged_task<void()> p2(p1);
Instead this constructor is a better match:
template <class F> explicit packaged_task(F&& f);
This attempts to package a packaged_task
, which internally tries to
copy p2
, which fails because the copy constructor is deleted. For at
least one implementation the resulting error message is much less
helpful than the expected "cannot call deleted function" because it
happens after instantiating several more templates rather than in the
context where the constructor is called.
F
cannot be deduced as (possibly cv)
packaged_task&
or packaged_task
. It could be argued
this constraint is already implied because packaged_task
is not
copyable and the template constructors require that "invoking a copy of f
shall behave the same as invoking f
".
Daniel points out that the variadic constructor of std::thread
described in 32.4.3.3 [thread.thread.constr] has a similar problem and
suggests a similar wording change, which has been integrated below.
An alternative is to declare thread(thread&)
and
packaged_task(packaged_task&)
as deleted.
[2012, Portland]
This issue appears to be more about library specification than technical concurrency issues, so should be handled in LWG.
[2013, Chicago]
Move to Immediate resolution.
Howard volunteered existing implementation experience with the first change, and saw no issue that the second would introduce any new issue.
Proposed resolution:
This wording is relative to the FDIS.
Insert a new Remarks element to 32.4.3.3 [thread.thread.constr] around p3 as indicated:
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
-3- Requires: F
and each Ti
in Args
shall satisfy the MoveConstructible
requirements. INVOKE(DECAY_COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
(20.8.2) shall be a valid expression.
decay<F>::type
is the same type as std::thread
.
Insert a new Remarks element to 32.10.10.2 [futures.task.members] around p2 as indicated:
template <class F> packaged_task(F&& f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
-2- Requires: INVOKE(f, t1, t2, ..., tN, R)
, where t1, t2, ..., tN
are values of the corresponding
types in ArgTypes...
, shall be a valid expression. Invoking a copy of f
shall behave the same as invoking f
.
decay<F>::type
is the same type as std::packaged_task<R(ArgTypes...)>
.