This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 3133. Modernizing numeric type requirements

Section: 28.2 [numeric.requirements] Status: C++20 Submitter: Tim Song Opened: 2018-07-05 Last modified: 2021-02-25

Priority: 0

View all other issues in [numeric.requirements].

View all issues with C++20 status.

Discussion:

28.2 [numeric.requirements] contains some very old wording that hasn't been changed since C++98 except for issue 2699. As a result, it is at once over- and under-restrictive. For example:

- It requires a class to have various member functions, but not that said member functions be actually callable (non-ambiguous, non-deleted) or called by the applicable operations;
- It doesn't disallow function or array types;
- It disallows ref-qualifiers on the assignment operator by restricting the signature;
- It bans unary `operator&` for class types, but not enumeration types; and
- It tries to impose semantic equivalence requirements on `T`'s special member functions, but doesn't require that copying produces an equivalent value to the original.

We can significantly clean up this wording by using the existing named requirements. For ease of review, the following table provides a side-by-side comparison of the current and proposed wording.

Before | After
--- | ---
A C++ program shall instantiate these components only with a type `T` that satisfies the following requirements: [Footnote … ] | A C++ program shall instantiate these components only with a cv-unqualified object type `T` that satisfies the Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable, and Cpp17Destructible following requirements (16.4.4.2 [utility.arg.requirements]).:
(1.1) — `T` is not an abstract class (it has no pure virtual member functions); | Cpp17DefaultConstructible
(1.2) — `T` is not a reference type; (1.3) — `T` is not cv-qualified; | Implied by "cv-unqualified object type"
(1.4) — If `T` is a class, it has a public default constructor; | Cpp17DefaultConstructible
(1.5) — If `T` is a class, it has a public copy constructor with the signature `T::T(const T&)`; | Cpp17CopyConstructible
(1.6) — If `T` is a class, it has a public destructor; | Cpp17Destructible
(1.7) — If `T` is a class, it has a public copy assignment operator whose signature is either `T& T::operator=(const T&)` or `T& T::operator=(T);` | Cpp17CopyAssignable
(1.8) — If `T` is a class, its assignment operator, copy and default constructors, and destructor shall correspond to each other in the following sense: (1.8.1) — Initialization of raw storage using the copy constructor on the value of `T()`, however obtained, is semantically equivalent to value-initialization of the same raw storage. (1.8.2) — Initialization of raw storage using the default constructor, followed by assignment, is semantically equivalent to initialization of raw storage using the copy constructor. (1.8.3) — Destruction of an object, followed by initialization of its raw storage using the copy constructor, is semantically equivalent to assignment to the original object. [Note: […] — end note] | These requirements are implied by Cpp17CopyConstructible and Cpp17CopyAssignable's requirement that the value of the copy is equivalent to the source.
(1.9) — If `T` is a class, it does not overload unary `operator&`. | omitted now that we have `std::addressof`

[2019-01-20 Reflector prioritization]

Set Priority to 0 and status to Tentatively Ready

Proposed resolution:

This wording is relative to the post-Rapperswil 2018 working draft.

1. Edit 28.2 [numeric.requirements] p1 as indicated, striking the entire bulleted list:

   > -1- The `complex` and `valarray` components are parameterized by the type of information they contain and manipulate. A C++ program shall instantiate these components only with a cv-unqualified object type `T` that satisfies the Cpp17DefaultConstructible, Cpp17CopyConstructible, Cpp17CopyAssignable, and Cpp17Destructible following requirements (16.4.4.2 [utility.arg.requirements]). :[Footnote: … ]

   > > (1.1) — `T` is not an abstract class (it has no pure virtual member functions);

   > > […]

   > > (1.9) — If `T` is a class, it does not overload unary `operator&`.

2. Edit 28.6.2.4 [valarray.access] p3-4 as indicated:

   >     const T&  operator[](size_t n) const;
   >     T& operator[](size_t n);

   > > -1- Requires: `n < size()`.

   > > -2- Returns: […]

   > > -3- Remarks: The expression `&addressof(a[i+j]) == &addressof(a[i]) + j` evaluates to `true` for all `size_t i` and `size_t j` such that `i+j < a.size()`.

   > > -4- The expression `&addressof(a[i]) != &addressof(b[j])` evaluates to `true` for any two arrays `a` and `b` and for any `size_t i` and `size_t j` such that `i < a.size()` and `j < b.size()`. [Note: […] — end note ]