allocator_arg_t
overloads of generator::promise_type::operator new
should not be constrainedSection: 25.8.5 [coro.generator.promise] Status: Ready Submitter: Tim Song Opened: 2023-03-04 Last modified: 2024-06-28
Priority: 3
View other active issues in [coro.generator.promise].
View all other issues in [coro.generator.promise].
View all issues with Ready status.
Discussion:
When the allocator is not type-erased, the allocator_arg_t
overloads of
generator::promise_type::operator new
are constrained on
convertible_to<const Alloc&, Allocator>
. As a result, if the
the allocator is default-constructible (like polymorphic_allocator
is)
but the user accidentally provided a wrong type (say, memory_resource&
instead of memory_resource*
), their code will silently fall back to
using a default-constructed allocator. It would seem better to take the tag
as definitive evidence of the user's intent to supply an allocator for the coroutine,
and error out if the supplied allocator cannot be used.
std::allocator_arg_t
tag) for their own use
inside the coroutine, but that sort of API seems fragile and confusing at best,
since the usual case is that allocators so passed will be used by
generator
.
[2023-03-22; Reflector poll]
Set priority to 3 after reflector poll.
[St. Louis 2024-06-28; move to Ready]
Proposed resolution:
This wording is relative to N4928.
Modify 25.8.5 [coro.generator.promise] as indicated:
[…]namespace std { template<class Ref, class V, class Allocator> class generator<Ref, V, Allocator>::promise_type { public: […] void* operator new(size_t size) requires same_as<Allocator, void> || default_initializable<Allocator>; template<class Alloc, class... Args>requires same_as<Allocator, void> || convertible_to<const Alloc&, Allocator>void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); template<class This, class Alloc, class... Args>requires same_as<Allocator, void> || convertible_to<const Alloc&, Allocator>void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, const Args&...); […] }; }void* operator new(size_t size) requires same_as<Allocator, void> || default_initializable<Allocator>; template<class Alloc, class... Args>requires same_as<Allocator, void> || convertible_to<const Alloc&, Allocator>void* operator new(size_t size, allocator_arg_t, const Alloc& alloc, const Args&...); template<class This, class Alloc, class... Args>requires same_as<Allocator, void> || convertible_to<const Alloc&, Allocator>void* operator new(size_t size, const This&, allocator_arg_t, const Alloc& alloc, const Args&...);-17- Let
A
be
(17.1) —
Allocator
, if it is notvoid
,(17.2) —
Alloc
for the overloads with a template parameterAlloc
, or(17.3) —
allocator<void>
otherwise.Let
-18- Mandates:B
beallocator_traits<A>::template rebind_alloc<U>
whereU
is an unspecified type whose size and alignment are both__STDCPP_DEFAULT_NEW_ALIGNMENT__
.allocator_traits<B>::pointer
is a pointer type. For the overloads with a template parameterAlloc
,same_as<Allocator, void> || convertible_to<const Alloc&, Allocator>
is modeled. -19- Effects: Initializes an allocatorb
of typeB
withA(alloc)
, for the overloads with a function parameteralloc
, and withA()
otherwise. Usesb
to allocate storage for the smallest array ofU
sufficient to provide storage for a coroutine state of sizesize
, and unspecified additional state necessary to ensure thatoperator delete
can later deallocate this memory block with an allocator equal tob
. -20- Returns: A pointer to the allocated storage.