uses_allocator_construction_args
unspecifiedSection: 20.2.8.2 [allocator.uses.construction] Status: C++23 Submitter: Casey Carter Opened: 2021-02-25 Last modified: 2023-11-22
Priority: 3
View all other issues in [allocator.uses.construction].
View all issues with C++23 status.
Discussion:
The synopsis of <memory>
in 20.2.2 [memory.syn] declares six overloads of
uses_allocator_construction_args
with return types "see below":
template<class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept -> see below; 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; template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept -> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept -> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept -> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept -> see below;
The "see belows" also appear in the detailed specification of these overloaded function templates in 20.2.8.2 [allocator.uses.construction] para 4 through 15. Despite that the values these function templates return are specified therein, the return types are not. Presumably LWG wanted to specify deduced return types, but couldn't figure out how to do so, and just gave up?
[2021-02-27; Daniel comments and provides wording]
My interpretation is that the appearance of the trailing-return-type was actually unintended and that
these functions where supposed to use the return type placeholder to signal the intention that the actual
return type is deduced by the consistent sum of all return statements as they appear in the prototype specifications.
Given that at least one implementation has indeed realized this form, I suggest to simply adjust the specification
to remove the trailing-return-type. Specification-wise we have already existing practice for this
approach (See e.g. to_address
).
[2021-03-12; Reflector poll]
Set priority to 3 following reflector poll.
[2021-05-26; Reflector poll]
Set status to Tentatively Ready after nine votes in favour during reflector poll.
[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4878.
Edit 20.2.2 [memory.syn], header <memory>
synopsis, as indicated:
namespace std { […] // 20.2.8.2 [allocator.uses.construction], uses-allocator construction template<class T, class Alloc, class... Args> constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept-> see below; 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; template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept-> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept-> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept-> see below; template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept-> see below; […] }
Edit 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;[…]
-5- Returns: Atuple
value determined as follows:
(5.1) — if […], return
forward_as_tuple(std::forward<Args>(args)...)
.(5.2) — Otherwise, if […], return
tuple<allocator_arg_t, const Alloc&, Args&&...>( allocator_arg, alloc, std::forward<Args>(args)...)(5.3) — Otherwise, if […], 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;[…]
-7- Effects: ForT
specified aspair<T1, T2>
, equivalent to:return make_tuple( piecewise_construct, apply([&alloc](auto&&... args1) { return uses_allocator_construction_args<T1>( alloc, std::forward<decltype(args1)>(args1)...); }, std::forward<Tuple1>(x)), apply([&alloc](auto&&... args2) { return uses_allocator_construction_args<T2>( alloc, std::forward<decltype(args2)>(args2)...); }, std::forward<Tuple2>(y)));template<class T, class Alloc> constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept-> see below;[…]
-9- Effects: Equivalent to:return uses_allocator_construction_args<T>(alloc, piecewise_construct, tuple<>{}, tuple<>{});template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept-> see below;[…]
-11- Effects: Equivalent to:return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(std::forward<U>(u)), forward_as_tuple(std::forward<V>(v));template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair<U, V>& pr) noexcept-> see below;[…]
-13- Effects: Equivalent to:return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(pr.first), forward_as_tuple(pr.second));template<class T, class Alloc, class U, class V> constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair<U, V>&& pr) noexcept-> see below;[…]
-15- Effects: Equivalent to:return uses_allocator_construction_args<T>(alloc, piecewise_construct, forward_as_tuple(std::move(pr).first), forward_as_tuple(std::move(pr).second));