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.
Section: 16.3.2.4 [structure.specifications] Status: New Submitter: Daniel Krügler Opened: 2019-03-04 Last modified: 2020-06-11
Priority: 3
View other active issues in [structure.specifications].
View all other issues in [structure.specifications].
View all issues with New status.
Discussion:
The working paper uses the special elements Mandates:, Expects: as well as Requires: to types, albeit 16.3.2.4 [structure.specifications] defines them only for functions, for example 16.3.2.4 [structure.specifications] sub-bullet (3.4):
Expects: the conditions (sometimes termed preconditions) that the function assumes to hold whenever it is called.
Examples for such usages on types are (from N4800):
23.2.3 [char.traits.typedefs] for types int_type and state_type
22.3.4 [pair.astuple] for tuple_element<I, pair<T1, T2>>::type
22.4.7 [tuple.helper] for tuple_element<I, tuple<Types...>>::type
22.4.11 [tuple.traits] for uses_allocator<tuple<Types...>, Alloc>
Table 62 — "Container requirements" for type XX::value_type
Table 65 — "Allocator-aware container requirements" for type allocator_type
Table 69 — "Associative container requirements" for types X::value_type and X::key_compare
Table 70 — "Unordered associative container requirements" for types X::value_type and X::key_equal
Instead of replacing these elements usages for these places by extra wording to reach the same effects I recommend to update instead 16.3.2.4 [structure.specifications] to ensure that requirement-expressing elements are defined in a way that it also allows to express requirements imposed on types by these elements to standardize "existing practice".
Considering details, it seems obvious that Mandates:, Expects: as well as Requires: are "suitable" to be defined for types (With the acceptance of P1463R1 there are now also Mandates: for types such as Table 65 — "Allocator-aware container requirements" for type allocator_type). For Constraints: the meaning would not be so clear: Should it mean that there is conditionally a type defined or not? According to the submitters knowledge there are currently no known examples for Constraints: to specify constraint on types, therefore I'm suggesting to restrict this extension to Mandates:, Expects:, and Requires: alone.[2019-03-15 Priority set to 3 after reflector discussion]
[2019-03-15; Daniel comments and provides wording]
During the preparation of the wording for this issue it was found that we should allow Remarks: elements to be used for other things than functions. One example of imposed restrictions can be found in 17.11.3 [cmp.common]:
template<class... Ts> struct common_comparison_category { using type = see below; };-2- Remarks: The member typedef-name type denotes the common comparison type (11.10.3 [class.spaceship]) of Ts..., the expanded parameter pack. […]
The discussion of this issue speaks of "type" restrictions (versus the specified restrictions on functions), because even the non-type template argument restrictions of 22.3.4 [pair.astuple] appear in the context of a member type specification, but there are examples where not really a single (member) type is involved, e.g. in the 22.4.7 [tuple.helper] example mentioned above.
Another example is when such elements are used for the specification of template specializations, e.g. in 22.4.7 [tuple.helper]:template<class T> struct tuple_size;-1- Remarks: All specializations of tuple_size shall satisfy the Cpp17UnaryTypeTrait requirements (21.3.2 [meta.rqmts]) with a base characteristic of integral_constant<size_t, N> for some N.
Besides class template specializations, a second relevant use-case is the specification of member types (Which are not necessarily part of a template), typically within the requirement tables, e.g. in Table 62 — "Container requirements"'s entry X::value_type:
Requires: T is Cpp17Erasable from X
The suggested wording tries to cover the generalization by means of the term "non-function entities" in addition to the existing functions to prevent being enforced to enumerate all entities to which the extended rules apply.
Previous resolution [SUPERSEDED]:This wording is relative to N4810.
Change 16.3.2.4 [structure.specifications], as indicated:
-3- Descriptions of function semantics contain the following elements (as appropriate); some of these elements may also appear in the description of non-function entities as denoted below: (footnote […])
(3.1) — Requires: the preconditions imposed on a non-function entity, or for calling the function.
(3.2) — Constraints: […]
(3.3) — Mandates: the conditions that, if not met, render the program ill-formed. [Example: An implementation might express such a condition via the constant-expression in a static_assert-declaration (Clause 9). If the diagnostic is to be emitted only after the function has been selected by overload resolution, an implementation might express such a condition via a constraint-expression (13.5.3 [temp.constr.decl]) and also define the function as deleted. — end example]
(3.4) — Expects: the conditions (sometimes termed preconditions) imposed on a non-function entity, or that the function assumes to hold whenever it is called. [Example: An implementation might express such conditions via an attribute such as [[expects]] ( [dcl.attr.contract]) on a function declaration. However, some such conditions might not lend themselves to expression via code. — end example]
[…]
(3.11) — Remarks: additional semantic constraints
on the function.[…]
Change 99 [res.on.required], as indicated:
-1- Violation of any preconditions specified in a
-2- Violation of any preconditions specified in anfunction'sRequires: element results in undefined behavior unless the function's Throws: element specifies throwing an exception whenthea function's precondition is violated.function'sExpects: element results in undefined behavior.
[2020-05-01; Daniel comments and adjusts wording to recent working draft]
It should be pointed out that the originally referred to Expects: element has since then be renamed to Preconditions: and that the Requires: element does now only occur in annex D.
[2020-06-11; Jonathan comments]
This issue also affects some type traits such as alignment_of and make_signed/make_unsigned. In addition to clarifying what Mandates: means on a non-function we need to decide exactly what is being mandated in the type traits. Is instantiating the class template ill-formed, or just odr-using the nested type or value member?
Proposed resolution:
This wording is relative to N4861.
Change 16.3.2.4 [structure.specifications], as indicated:
-3- Descriptions of function semantics contain the following elements (as appropriate); some of these elements may also appear in the description of non-function entities as denoted below: (footnote […])
(3.1) — Constraints: […]
(3.2) — Mandates: the conditions that, if not met, render the program ill-formed. [Example: An implementation might express such a condition via the constant-expression in a static_assert-declaration (9.1 [dcl.pre]). If the diagnostic is to be emitted only after the function has been selected by overload resolution, an implementation might express such a condition via a constraint-expression (13.5.3 [temp.constr.decl]) and also define the function as deleted. — end example]
(3.3) — Preconditions: the conditions imposed on a non-function entity, or that the function assumes to hold whenever it is called.
[…]
(3.10) — Remarks: additional semantic constraints
on the function.[…]
Change [res.on.expects], as indicated:
-1- Violation of any preconditions specified in a
function'sPreconditions: element results in undefined behavior.
Change D.11 [depr.res.on.required], as indicated:
[Drafting note: Interestingly, albey the Requires: element has nearly vanished, the issue is still relevant, see D.19 [depr.meta.types]]
-1- Violation of any preconditions specified in a
function'sRequires: element results in undefined behavior unless the function's Throws: element specifies throwing an exception whenthea function's precondition is violated.