This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
allocator_arg_t overloads of generator::promise_type::operator new
should not be constrainedSection: 25.8.5 [coro.generator.promise] Status: WP Submitter: Tim Song Opened: 2023-03-04 Last modified: 2024-11-28
Priority: 3
View all other issues in [coro.generator.promise].
View all issues with WP 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]
[Wrocław 2024-11-23; Status changed: Voting → WP.]
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
Abe
(17.1) —
Allocator, if it is notvoid,(17.2) —
Allocfor the overloads with a template parameterAlloc, or(17.3) —
allocator<void>otherwise.Let
-18- Mandates:Bbeallocator_traits<A>::template rebind_alloc<U>whereUis an unspecified type whose size and alignment are both__STDCPP_DEFAULT_NEW_ALIGNMENT__.allocator_traits<B>::pointeris 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 allocatorbof typeBwithA(alloc), for the overloads with a function parameteralloc, and withA()otherwise. Usesbto allocate storage for the smallest array ofUsufficient to provide storage for a coroutine state of sizesize, and unspecified additional state necessary to ensure thatoperator deletecan later deallocate this memory block with an allocator equal tob. -20- Returns: A pointer to the allocated storage.