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.

3888. Most ranges uninitialized memory algorithms are underconstrained

Section: 27.11.8 [specialized.construct] Status: New Submitter: Jiang An Opened: 2023-02-17 Last modified: 2023-03-22

Priority: 3

View other active issues in [specialized.construct].

View all other issues in [specialized.construct].

View all issues with New status.


LWG 3870 removed the support for constructing objects via cv-qualified lvalues. However, it had not changed anything in the immediate context, which means some previously permitted usages become hard errors instead of substitution failures.

Note that ranges::uninitialized_default_construct and ranges::uninitialized_default_construct_n are underconstrained even before LWG 3870, because remove_reference_t<iter_reference_t<I>> may be a const type, while only it's cv-unqualified version (iter_value_t<I>) is required to be default_initializable.

construct_at and ranges::construct_at are also made underconstrained because the function body is no longer valid when T is cv-qualified, which is not reflected in Constraints:.

[2023-03-22; Reflector poll]

Set priority to 3 after reflector poll.

Proposed resolution:

This wording is relative to N4928.

  1. Modify 27.11.2 [special.mem.concepts] as indicated:

    template<class I>
    concept nothrow-input-iterator = // exposition only
      input_iterator<I> &&
      is_lvalue_reference_v<iter_reference_t<I>> &&
      same_as<remove_cvref_t<iter_reference_t<I>>, remove_reference_t<iter_reference_t<I>> &&
      same_as<remove_cvref_t<iter_reference_t<I>>, iter_value_t<I>>;
  2. Modify 27.11.8 [specialized.construct] as indicated:

    template<class T, class... Args>
      constexpr T* construct_at(T* location, Args&&... args);
    namespace ranges {
      template<class T, class... Args>
        constexpr T* construct_at(T* location, Args&&... args);

    -1- Constraints: T is a cv-unqualified type, and tThe expression ::new (declval<void*>()) T(declval<Args>()...) is well-formed when treated as an unevaluated operand (7.2.3 [expr.context]).

    -2- Effects: Equivalent to:

    return ::new (voidify(*location)) T(std::forward<Args>(args)...);