Wording for “functionality gaps in constraints” (original) (raw)

This paper contains formal wording for the two extensions proposed inP0766r1: Fixing small-ish functionality gaps in constraints that concern _requires-clause_s.

Proposed wording for constrained lambdas

Modify the grammar in [expr.prim.lambda, 8.1.5] as follows.

lambda-expression:
lambda-introducer compound-statement
lambda-introducer lambda-declaratoropt _requires-clause_opt compound-statement
lambda-introducer < template-parameter-list > _requires-clause_opt compound-statement
lambda-introducer < template-parameter-list > _requires-clause_opt lambda-declaratoropt _requires-clause_opt compound-statement

Modify [expr.prim.lambda, 8.1.5] paragraph 3 as follows.

In the decl-specifier-seq of the lambda-declarator, each decl-specifier shall either be mutable or constexpr.[Note: The trailing requires-clause is described in Clause [dcl.decl, 11]. – _end note_]

Modify [expr.prim.lambda, 8.1.5.1] paragraph 3 as follows.

The closure type for a non-generic lambda-expression has a public inline function call operator (16.5.4) whose parameters and return type are described by the _lambda-expression_’s parameter-declaration-clause and trailing-return-type respectively. For a generic lambda, the closure type has a public inline function call operator member template (17.6.2) whose template-parameter-list consists of the specified template-parameter-list, if any, to which is appended one invented type template-parameter for each occurrence ofauto in the lambda’s parameter-declaration-clause, in order of appearance. The invented type template-parameter is a parameter pack if the corresponding parameter-declaration declares a function parameter pack (11.3.5). The return type and function parameters of the function call operator template are derived from the _lambda-expression_’s trailing-return-type and parameter-declaration-clause by replacing each occurrence of auto in the decl-specifiers of the parameter-declaration-clause with the name of the corresponding invented template-parameter.The requires-clause of the function call operator template is the requires-clause immediately following < template-parameter-list >, if any. The trailing requires-clause of the function call operator or operator template is the requires-clause following the lambda-declarator, if any. [Example: […]

Modify [expr.prim.lambda, 8.1.5.1] paragraph 6 as follows.

The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (10.5) having the same parameter and return types as the closure type’s function call operator. The conversion is to “pointer to noexcept function” if the function call operator has a non-throwing exception specification. The value returned by this conversion function is the address of a function F that, when invoked, has the same effect as […]

Insert a new paragraph between paragraphs 5 and 6 of [expr.prim.lambda.closure, 8.1.5.1].

[…] – _end example_]

The function call operator or operator template may be constrained ([temp.constr.decl, 17.4.2]) by a constrained-parameter ([temp.param, 17.1]), a requires-clause (Clause [temp, 17]), or a trailing requires-clause (Clause [dcl.decl, 11]). [Example:

template concept C1 = /* ... */; template <std::size_t N> concept C2 = /* ... */; template <typename A, typename B> concept C3 = /* ... */; auto f = []<typename T1, C1 T2> requires C2<sizeof(T1) + sizeof(T2)> (T1 a1, T1 b1, T2 a2, auto a3, auto a4) requires C3<decltype(a4), T2> { // T2 is a constrained parameter, // T1 and T2 are constrained by a requires-clause, and // T2 and the type of a4 are constrained by a trailing requires-clause. };

– _end example_]

The closure type for a non-generic lambda-expression […]

Proposed wording for constrained template _template-parameter_s

Modify the grammar in [temp.param, 17.1] as follows.

template-parameter:
[…]

type-parameter:
type-parameter-key ...opt _identifier_opt
type-parameter-key _identifier_opt = type-id
template < template-parameter-list >template-head type-parameter-key ...opt _identifier_opt
template < template-parameter-list >template-head type-parameter-key _identifier_opt = id-expression

type-parameter-key:
[…]

Modify [temp.arg.template, 17.3.3], paragraph 3 as follows.

A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A. If P contains a parameter pack, then A also matches P if each of A’s template parameters matches the corresponding template parameter in the template-parameter-listtemplate-head of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (17.6.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively. When P’s template-parameter-listtemplate-head contains a template parameter pack (17.6.3), the template parameter pack will match zero or more template parameters or template parameter packs in the_template-parameter-listtemplate-head_ of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs). [Example: […]

Modify [temp.arg.template, 17.3.3], paragraph 4 as follows.

A template template-parameter P is at least as specialized as a template template-argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the partial ordering rules for function templates (17.6.6.2). Given an invented class template X with the template parameter listtemplate-head of A (including default arguments and requires-clause, if any):

If the rewrite produces an invalid type, then P is not at least as specialized as A.