This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 20.2.8.2 [allocator.uses.construction] Status: New Submitter: Jonathan Wakely Opened: 2019-02-28 Last modified: 2020-05-01
Priority: 3
View all other issues in [allocator.uses.construction].
View all issues with New status.
Discussion:
The new functions added by P0591R4 misbehave for cv-qualified types. A specialization std::uses_allocator<X, Alloc> will not match const X, so std::uses_allocator_construction_args<const X> will return a different result from std::uses_allocator_construction_args<X>. It makes no sense to construct X and const X differently, either the type wants to use an allocator or it doesn't. I think std::uses_allocator_construction_args<T> should remove cv-qualifiers before checking uses_allocator, so that it works consistently.
We could consider changing std::make_obj_using_allocator to also strip cv-qualifiers, but it's not necessary as C++17 guaranteed elision works even for prvalues of const types. We only need to make the construction args ignore cv-qualifiers. We don't want to make cv-qualified types ill-formed, because that would require users of uses-allocator construction to strip cv-qualifiers before using these functions, e.g. in cases like std::tuple<const int> t(allocator_arg, alloc, 1);[2019-03-15 Priority set to 3 after reflector discussion]
Previous resolution [SUPERSEDED]:This wording is relative to N4800.
Change 20.2.8.2 [allocator.uses.construction] as indicated:
template <class T, class Alloc, class... Args> auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) -> see below;[…]-4- Constraints: T is not a specialization of pair.
-5- Returns: A tuple value determined as follows, where U denotes the type remove_cv_t<T>:
(5.1) — If uses_allocator_v<
TU, Alloc> is false and is_constructible_v<T, Args...> is true, return forward_as_tuple(std::forward<Args>(args)...).(5.2) — Otherwise, if uses_allocator_v<
TU, Alloc> is true and is_constructible_v<T, allocator_arg_t, Alloc, Args...> is true, returntuple<allocator_arg_t, const Alloc&, Args&&...>( allocator_arg, alloc, std::forward<Args>(args)...)(5.3) — Otherwise, if uses_allocator_v<
TU, Alloc> is true and is_constructible_v<T, Args..., Alloc> is true, return forward_as_tuple(std::forward<Args>(args)..., alloc).(5.4) — Otherwise, the program is ill-formed.
template <class T, class Alloc, class Tuple1, class Tuple2> auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) -> see below;-6- Constraints: T is a specialization of pair.
-7- Effects: For T specified as (possibly const) pair<T1, T2>, equivalent to: […]template <class T, class Alloc, class... Args> T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args);-17- Effects: Equivalent to:
return ::new(static_cast<void*>voidify(*p)) T(make_obj_using_allocator<T>(alloc, std::forward<Args>(args)...));
[2020-05-01; Daniel syncs wording with recent working draft]
The previously needed change for uninitialized_construct_using_allocator is no longer required, because the reworded call to construct_at does do the right thing now.
Proposed resolution:
This wording is relative to N4861.
Change 20.2.8.2 [allocator.uses.construction] as indicated:
template <class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept -> see below;[…]-4- Constraints: T is not a specialization of pair.
-5- Returns: A tuple value determined as follows, where U denotes the type remove_cv_t<T>:
(5.1) — If uses_allocator_v<
TU, Alloc> is false and is_constructible_v<T, Args...> is true, return forward_as_tuple(std::forward<Args>(args)...).(5.2) — Otherwise, if uses_allocator_v<
TU, Alloc> is true and is_constructible_v<T, allocator_arg_t, const Alloc&, Args...> is true, returntuple<allocator_arg_t, const Alloc&, Args&&...>( allocator_arg, alloc, std::forward<Args>(args)...)(5.3) — Otherwise, if uses_allocator_v<
TU, Alloc> is true and is_constructible_v<T, Args..., const Alloc&> is true, return forward_as_tuple(std::forward<Args>(args)..., alloc).(5.4) — Otherwise, the program is ill-formed.
template <class T, class Alloc, class Tuple1, class Tuple2> constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept -> see below;-6- Constraints: T is a specialization of pair.
-7- Effects: For T specified as (possibly const) pair<T1, T2>, equivalent to: […]