3477. Simplify constraints for semiregular-box

Section: 25.7.3 [range.move.wrap] Status: C++23 Submitter: Casey Carter Opened: 2020-08-19 Last modified: 2023-11-22

Priority: 0

View all other issues in [range.move.wrap].

View all issues with C++23 status.

Discussion:

The exposition-only semiregular-box class template specified in [range.semi.wrap] implements a default constructor, copy assignment operator, and move assignment operator atop the facilities provided by std::optional when the wrapped type is not default constructible, copy assignable, or move assignable (respectively). The constraints on the copy and move assignment operator implementations go out of their way to be unnecessarily minimal. The meaning of the constraint on the copy assignment operator — !assignable<T, const T&> — has even changed since this wording was written as a result of LWG reformulating the implicit expression variations wording in 18.2 [concepts.equality].

It would be much simpler for implementors and users if we recall that minimality is not the primary goal of constraints and instead constrain these assignment operators more simply with !movable<T> and !copyable<T>.

[2020-09-03; Reflector prioritization]

Set priority to 0 and status to Tentatively Ready after six votes in favour during reflector discussions.

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

  1. Modify [range.semi.wrap] as indicated:

    -1- Many types in this subclause are specified in terms of an exposition-only class template semiregular-box. semiregular-box<T> behaves exactly like optional<T> with the following differences:

    1. (1.1) — […]

    2. (1.2) — […]

    3. (1.3) — If assignable_from<T&, const T&>copyable<T> is not modeled, the copy assignment operator is equivalent to:

      semiregular-box& operator=(const semiregular-box& that)
        noexcept(is_nothrow_copy_constructible_v<T>)
      {
        if (that) emplace(*that);
        else reset();
        return *this;
      }
      
    4. (1.4) — If assignable_from<T&, T>movable<T> is not modeled, the move assignment operator is equivalent to:

      semiregular-box& operator=(semiregular-box&& that)
        noexcept(is_nothrow_move_constructible_v<T>)
      {
        if (that) emplace(std::move(*that));
        else reset();
        return *this;
      }