Title
Return types of uses_allocator_construction_args unspecified
Status
new
Section
[allocator.uses.construction]
Submitter
Casey Carter

Created on 2021-02-25.00:00:00 last changed 1 month ago

Messages

Date: 2021-03-12.15:07:58

Proposed resolution:

This wording is relative to N4878.

  1. Edit [memory.syn], header <memory> synopsis, as indicated:

    namespace std {
      […]
      // [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;   
      […]
    }
    
  2. Edit [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: A tuple value determined as follows:

    1. (5.1) — if […], return forward_as_tuple(std::forward<Args>(args)...).

    2. (5.2) — Otherwise, if […], return

      tuple<allocator_arg_t, const Alloc&, Args&&...>(
        allocator_arg, alloc, std::forward<Args>(args)...)
      
    3. (5.3) — Otherwise, if […], return forward_as_tuple(std::forward<Args>(args)..., alloc).

    4. (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: For T specified as pair<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));
    
Date: 2021-03-15.00:00:00

[ 2021-03-12; Reflector poll ]

Set priority to 3 following reflector poll.

Date: 2021-02-15.00:00:00

[ 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).

Date: 2021-02-25.00:00:00

The synopsis of <memory> in [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 [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?

History
Date User Action Args
2021-03-12 15:07:58adminsetmessages: + msg11730
2021-02-27 15:28:58adminsetmessages: + msg11713
2021-02-27 15:28:58adminsetmessages: + msg11712
2021-02-25 00:00:00admincreate