Created on 2017-07-16.00:00:00 last changed yesterday
Proposed resolution:
This wording is relative to N4988.
Modify [futures.promise] as indicated:
[…]template <class R, class Alloc> struct uses_allocator<promise<R>, Alloc>;template <class R, class Alloc> struct uses_allocator<promise<R>, Alloc> : true_type { };
-4- Preconditions: Alloc meets the Cpp17Allocator ([allocator.requirements.general]).
Modify [futures.task.general] as indicated:
template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)> { public: // construction and destruction packaged_task() noexcept; template<class F> explicit packaged_task(F&& f); template<class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task();
Modify [futures.task.members] as indicated:
template<class F> explicit packaged_task(F&& f);-?- Effects: Equivalent to
packaged_task(allocator_arg, std::allocator<int>(), std::forward<F>(f))
.[Drafting note: Uses ofstd::allocator<int>
andstd::allocator<unspecified>
are not observable so this constructor can be implemented without delegating to the other constructor and without using `std::allocator`.]template<class F, class Allocator> packaged_task(allocator_arg_t, const Allocator& a, F&& f);-2- Constraints:
remove_cvref_t<F>
is not the same type aspackaged_task<R(ArgTypes...)>
.-3- Mandates:
is_invocable_r_v<R, F&, ArgTypes...>
istrue
.[Drafting note: Issue 4154 alters these Mandates: and Effects: but the two edits should combine cleanly.]-4- Preconditions: Invoking a copy of `f` behaves the same as invoking `f`. `Allocator` meets the Cpp17Allocator requirements ([allocator.requirements.general]).
-5- Effects: Let `A2` be
allocator_traits<Allocator>::rebind_alloc<unspecified>
and let `a2` be an lvalue of type `A2` initialized with `A2(a)`. Creates a shared state and initializes the object's stored task withstd::forward<F>(f)
. Uses `a2` to allocate storage for the shared state and stores a copy of `a2` in the shared state.-6- Throws:
Any exceptions thrown by the copy or move constructor of `f`, or bad_alloc if memory for the internal data structures cannot be allocated.Any exceptions thrown by the initialization of the stored task. If storage for the shared state cannot be allocated, any exception thrown by `A2::allocate`.…
void reset();-26- Effects:
As ifEquivalent to:if (!valid()) throw future_error(future_errc::no_state); *this = packaged_task(allocator_arg, a, std::move(f));where `f` is the task stored in `*this` and `a` is the allocator stored in the shared state.[Note 2: This constructs a new shared state for `*this`. The old state is abandoned ([futures.state]). — end note]
-27- Throws:
(27.1) — bad_alloc if memory for the new shared state cannot be allocated.- (27.2) — Any exception thrown by the `packaged_task` constructor
move constructor of the task stored in the shared state.- (27.3) — `future_error` with an error condition of `no_state` if `*this` has no shared state.
[ Wrocław 2024-11-18; LEWG would prefer a paper for this ]
[ 2024-09-19; Jonathan provides improved wording ]
In July 2023 LEWG considered this and LWG issue 2095 and requested a new proposed resolution that kept the existing constructor (which is useful for controlling how the shared state is allocated) but removed the `uses_allocator` specialization that makes `promise` incorrectly claim to be allocator-aware. Some of the rationale in P2787R1 is applicable here too.
Without the `uses_allocator` specialization, there's no reason to provide an allocator-extended move constructor, resolving issue 2095.
And if we're going to continue supporting `std::promise` construction with an allocator, we could restore that for `std::packaged_task` too. That was removed by issue 2921, but issue 2976 argues that there was no good reason to do that. Removing `uses_allocator` for `packaged_task` would have made sense (as proposed below for `promise`) but 2921 didn't do that (which is why 2976 was needed). We can restore the `packaged_task` constructor that takes an allocator, and just not restore the `uses_allocator` specialization that implies it should be fully allocator-aware. Finally, if we restore that `packaged_task` constructor then we need to fix `reset()` as discussed in issue 2245.
In summary:
[ Varna 2023-06-13; Change status to "LEWG" ]
This resolution is relative to N4659.
Edit [futures.promise], class template promise synopsis, as indicated:
template<class R> class promise { public: promise();[…]template <class Allocator> promise(allocator_arg_t, const Allocator& a);[…] }; template <class R> void swap(promise<R>& x, promise<R>& y) noexcept;template <class R, class Alloc> struct uses_allocator<promise<R>, Alloc>;template <class R, class Alloc> struct uses_allocator<promise<R>, Alloc> : true_type { };
-3- Requires: Alloc shall be an Allocator ([allocator.requirements]).promise();template <class Allocator> promise(allocator_arg_t, const Allocator& a);-4- Effects: constructs a promise object and a shared state.
The second constructor uses the allocator a to allocate memory for the shared state.
[ 2019-06-03 ]
Jonathan observes that this resolution conflicts with 2095.
[ 2018-1-26 issues processing telecon ]
Status to 'Open'; Billy to write a paper.
[ 28-Nov-2017 Mailing list discussion - set priority to P2 ]
Lots of people on the ML feel strongly about this; the suggestion was made that a paper would be welcomed laying out the rationale for removing allocator support here (and in other places).
In Toronto Saturday afternoon LWG discussed LWG 2976 which finishes the job of removing allocator support from packaged_task. LWG confirmed that, despite the removal of packaged_task allocators "because it looks like std::function" was incorrect, they wanted to keep the allocator removals anyway, in large part due to this resolution being a response to an NB comment.
If we don't want the type erased allocator situation at all, then we should remove them from the remaining place they exist in <future>, namely, in promise. This change also resolves potential implementation divergence on whether allocator::construct is intended to be used on elements constructed in the shared state, and allows the emplace-construction-in-future paper, p0319, to be implemented without potential problems there.History | |||
---|---|---|---|
Date | User | Action | Args |
2024-11-19 16:09:33 | admin | set | messages: + msg14460 |
2024-09-20 12:40:58 | admin | set | messages: + msg14393 |
2024-09-20 12:26:44 | admin | set | messages: + msg14392 |
2024-09-20 12:26:44 | admin | set | status: open -> lewg |
2019-06-03 09:53:27 | admin | set | messages: + msg10413 |
2018-01-28 19:43:07 | admin | set | messages: + msg9656 |
2018-01-28 19:43:07 | admin | set | status: new -> open |
2017-11-29 03:09:11 | admin | set | messages: + msg9570 |
2017-07-16 14:02:00 | admin | set | messages: + msg9412 |
2017-07-16 00:00:00 | admin | create |