- tmp/tmp7j1qqjfq/{from.md → to.md} +107 -87
tmp/tmp7j1qqjfq/{from.md → to.md}
RENAMED
|
@@ -3,12 +3,12 @@
|
|
| 3 |
There are three forms of *template-argument*, corresponding to the three
|
| 4 |
forms of *template-parameter*: type, non-type and template. The type and
|
| 5 |
form of each *template-argument* specified in a *template-id* shall
|
| 6 |
match the type and form specified for the corresponding parameter
|
| 7 |
declared by the template in its *template-parameter-list*. When the
|
| 8 |
-
parameter declared by the template is a template parameter pack
|
| 9 |
-
[[temp.variadic]]
|
| 10 |
*template-argument*s.
|
| 11 |
|
| 12 |
[*Example 1*:
|
| 13 |
|
| 14 |
``` cpp
|
|
@@ -93,11 +93,11 @@ template <template <class TT> class T> class A {
|
|
| 93 |
template <class U> class B {
|
| 94 |
private:
|
| 95 |
struct S { ... };
|
| 96 |
};
|
| 97 |
|
| 98 |
-
A<B> b; //
|
| 99 |
```
|
| 100 |
|
| 101 |
— *end example*]
|
| 102 |
|
| 103 |
When template argument packs or default *template-argument*s are used, a
|
|
@@ -115,12 +115,12 @@ Tuple<>* t; // OK: Elements is empty
|
|
| 115 |
Tuple* u; // syntax error
|
| 116 |
```
|
| 117 |
|
| 118 |
— *end example*]
|
| 119 |
|
| 120 |
-
An explicit destructor call
|
| 121 |
-
|
| 122 |
*template-argument*s.
|
| 123 |
|
| 124 |
[*Example 6*:
|
| 125 |
|
| 126 |
``` cpp
|
|
@@ -137,18 +137,18 @@ void f(A<int>* p, A<int>* q) {
|
|
| 137 |
|
| 138 |
If the use of a *template-argument* gives rise to an ill-formed
|
| 139 |
construct in the instantiation of a template specialization, the program
|
| 140 |
is ill-formed.
|
| 141 |
|
| 142 |
-
When the
|
| 143 |
both non-template functions in the overload set and function templates
|
| 144 |
in the overload set for which the *template-argument*s do not match the
|
| 145 |
*template-parameter*s are ignored. If none of the function templates
|
| 146 |
have matching *template-parameter*s, the program is ill-formed.
|
| 147 |
|
| 148 |
When a *simple-template-id* does not name a function, a default
|
| 149 |
-
*template-argument* is implicitly instantiated
|
| 150 |
value of that default argument is needed.
|
| 151 |
|
| 152 |
[*Example 7*:
|
| 153 |
|
| 154 |
``` cpp
|
|
@@ -159,12 +159,12 @@ S<bool>* p; // the type of p is S<bool, int>*
|
|
| 159 |
The default argument for `U` is instantiated to form the type
|
| 160 |
`S<bool, int>*`.
|
| 161 |
|
| 162 |
— *end example*]
|
| 163 |
|
| 164 |
-
A *template-argument* followed by an ellipsis is a pack expansion
|
| 165 |
-
[[temp.variadic]]
|
| 166 |
|
| 167 |
### Template type arguments <a id="temp.arg.type">[[temp.arg.type]]</a>
|
| 168 |
|
| 169 |
A *template-argument* for a *template-parameter* which is a type shall
|
| 170 |
be a *type-id*.
|
|
@@ -190,37 +190,45 @@ void f() {
|
|
| 190 |
}
|
| 191 |
```
|
| 192 |
|
| 193 |
— *end example*]
|
| 194 |
|
| 195 |
-
[*Note 1*: A template type argument may be an incomplete type
|
| 196 |
-
[[basic.types]]
|
| 197 |
|
| 198 |
### Template non-type arguments <a id="temp.arg.nontype">[[temp.arg.nontype]]</a>
|
| 199 |
|
| 200 |
-
If the type of a *template-parameter* contains a
|
| 201 |
-
[[dcl.spec.auto]]
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
|
| 207 |
A *template-argument* for a non-type *template-parameter* shall be a
|
| 208 |
-
converted constant expression
|
| 209 |
-
*template-parameter*.
|
| 210 |
-
or pointer type, the value of the constant expression shall not refer to
|
| 211 |
-
(or for a pointer type, shall not be the address of):
|
| 212 |
|
| 213 |
-
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
- the result of a `typeid` expression ([[expr.typeid]]), or
|
| 217 |
-
- a predefined `__func__` variable ([[dcl.fct.def.general]]).
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
[*Example 1*:
|
| 224 |
|
| 225 |
``` cpp
|
| 226 |
template<const int* pci> struct X { ... };
|
|
@@ -242,76 +250,67 @@ void f(int);
|
|
| 242 |
template<void (*pf)(int)> struct A { ... };
|
| 243 |
|
| 244 |
A<&f> a; // selects f(int)
|
| 245 |
|
| 246 |
template<auto n> struct B { ... };
|
| 247 |
-
B<5> b1; // OK
|
| 248 |
-
B<'a'> b2; // OK
|
| 249 |
-
B<2.5> b3; //
|
|
|
|
| 250 |
```
|
| 251 |
|
| 252 |
— *end example*]
|
| 253 |
|
| 254 |
[*Note 2*:
|
| 255 |
|
| 256 |
-
A string
|
| 257 |
-
*template-argument*.
|
| 258 |
|
| 259 |
[*Example 2*:
|
| 260 |
|
| 261 |
``` cpp
|
| 262 |
-
template<class T,
|
| 263 |
...
|
| 264 |
};
|
| 265 |
|
| 266 |
-
X<
|
|
|
|
| 267 |
|
| 268 |
const char p[] = "Vivisectionist";
|
| 269 |
-
X<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
```
|
| 271 |
|
| 272 |
— *end example*]
|
| 273 |
|
| 274 |
— *end note*]
|
| 275 |
|
| 276 |
[*Note 3*:
|
| 277 |
|
| 278 |
-
The address of an array element or non-static data member is not an
|
| 279 |
-
acceptable *template-argument*.
|
| 280 |
-
|
| 281 |
-
[*Example 3*:
|
| 282 |
-
|
| 283 |
-
``` cpp
|
| 284 |
-
template<int* p> class X { };
|
| 285 |
-
|
| 286 |
-
int a[10];
|
| 287 |
-
struct S { int m; static int s; } s;
|
| 288 |
-
|
| 289 |
-
X<&a[2]> x3; // error: address of array element
|
| 290 |
-
X<&s.m> x4; // error: address of non-static member
|
| 291 |
-
X<&s.s> x5; // OK: address of static member
|
| 292 |
-
X<&S::s> x6; // OK: address of static member
|
| 293 |
-
```
|
| 294 |
-
|
| 295 |
-
— *end example*]
|
| 296 |
-
|
| 297 |
-
— *end note*]
|
| 298 |
-
|
| 299 |
-
[*Note 4*:
|
| 300 |
-
|
| 301 |
A temporary object is not an acceptable *template-argument* when the
|
| 302 |
corresponding *template-parameter* has reference type.
|
| 303 |
|
| 304 |
-
[*Example
|
| 305 |
|
| 306 |
``` cpp
|
| 307 |
template<const int& CRI> struct B { ... };
|
| 308 |
|
| 309 |
-
B<1>
|
| 310 |
|
| 311 |
int c = 1;
|
| 312 |
-
B<c>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
```
|
| 314 |
|
| 315 |
— *end example*]
|
| 316 |
|
| 317 |
— *end note*]
|
|
@@ -324,11 +323,11 @@ name of a class template or an alias template, expressed as
|
|
| 324 |
only primary class templates are considered when matching the template
|
| 325 |
template argument with the corresponding parameter; partial
|
| 326 |
specializations are not considered even if their parameter lists match
|
| 327 |
that of the template template parameter.
|
| 328 |
|
| 329 |
-
Any partial specializations
|
| 330 |
primary class template or primary variable template are considered when
|
| 331 |
a specialization based on the template *template-parameter* is
|
| 332 |
instantiated. If a specialization is not visible at the point of
|
| 333 |
instantiation, and it would have been selected had it been visible, the
|
| 334 |
program is ill-formed, no diagnostic required.
|
|
@@ -351,24 +350,25 @@ C<A> c; // V<int> within C<A> uses the primary template, so c.y.x ha
|
|
| 351 |
```
|
| 352 |
|
| 353 |
— *end example*]
|
| 354 |
|
| 355 |
A *template-argument* matches a template *template-parameter* `P` when
|
| 356 |
-
`P` is at least as specialized as the *template-argument* `A`.
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
*template-parameter*s
|
| 364 |
-
*template-parameter
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
template parameter pack in `P`
|
| 369 |
-
parameters are template parameter
|
|
|
|
| 370 |
|
| 371 |
[*Example 2*:
|
| 372 |
|
| 373 |
``` cpp
|
| 374 |
template<class T> class A { ... };
|
|
@@ -411,27 +411,47 @@ eval<D<int, 17>> eD; // error: D does not match TT in partial special
|
|
| 411 |
eval<E<int, float>> eE; // error: E does not match TT in partial specialization
|
| 412 |
```
|
| 413 |
|
| 414 |
— *end example*]
|
| 415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
A template *template-parameter* `P` is at least as specialized as a
|
| 417 |
template *template-argument* `A` if, given the following rewrite to two
|
| 418 |
function templates, the function template corresponding to `P` is at
|
| 419 |
least as specialized as the function template corresponding to `A`
|
| 420 |
-
according to the partial ordering rules for function templates
|
| 421 |
-
[[temp.func.order]]
|
| 422 |
-
template
|
|
|
|
| 423 |
|
| 424 |
-
- Each of the two function templates has the same template parameters
|
| 425 |
-
respectively, as `P` or `A`.
|
| 426 |
- Each function template has a single function parameter whose type is a
|
| 427 |
specialization of `X` with template arguments corresponding to the
|
| 428 |
template parameters from the respective function template where, for
|
| 429 |
-
each template parameter `PP` in the template
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
`PP...`
|
| 433 |
`PP`.
|
| 434 |
|
| 435 |
If the rewrite produces an invalid type, then `P` is not at least as
|
| 436 |
specialized as `A`.
|
| 437 |
|
|
|
|
| 3 |
There are three forms of *template-argument*, corresponding to the three
|
| 4 |
forms of *template-parameter*: type, non-type and template. The type and
|
| 5 |
form of each *template-argument* specified in a *template-id* shall
|
| 6 |
match the type and form specified for the corresponding parameter
|
| 7 |
declared by the template in its *template-parameter-list*. When the
|
| 8 |
+
parameter declared by the template is a template parameter pack
|
| 9 |
+
[[temp.variadic]], it will correspond to zero or more
|
| 10 |
*template-argument*s.
|
| 11 |
|
| 12 |
[*Example 1*:
|
| 13 |
|
| 14 |
``` cpp
|
|
|
|
| 93 |
template <class U> class B {
|
| 94 |
private:
|
| 95 |
struct S { ... };
|
| 96 |
};
|
| 97 |
|
| 98 |
+
A<B> b; // error: A has no access to B::S
|
| 99 |
```
|
| 100 |
|
| 101 |
— *end example*]
|
| 102 |
|
| 103 |
When template argument packs or default *template-argument*s are used, a
|
|
|
|
| 115 |
Tuple* u; // syntax error
|
| 116 |
```
|
| 117 |
|
| 118 |
— *end example*]
|
| 119 |
|
| 120 |
+
An explicit destructor call [[class.dtor]] for an object that has a type
|
| 121 |
+
that is a class template specialization may explicitly specify the
|
| 122 |
*template-argument*s.
|
| 123 |
|
| 124 |
[*Example 6*:
|
| 125 |
|
| 126 |
``` cpp
|
|
|
|
| 137 |
|
| 138 |
If the use of a *template-argument* gives rise to an ill-formed
|
| 139 |
construct in the instantiation of a template specialization, the program
|
| 140 |
is ill-formed.
|
| 141 |
|
| 142 |
+
When name lookup for the name in a *template-id* finds an overload set,
|
| 143 |
both non-template functions in the overload set and function templates
|
| 144 |
in the overload set for which the *template-argument*s do not match the
|
| 145 |
*template-parameter*s are ignored. If none of the function templates
|
| 146 |
have matching *template-parameter*s, the program is ill-formed.
|
| 147 |
|
| 148 |
When a *simple-template-id* does not name a function, a default
|
| 149 |
+
*template-argument* is implicitly instantiated [[temp.inst]] when the
|
| 150 |
value of that default argument is needed.
|
| 151 |
|
| 152 |
[*Example 7*:
|
| 153 |
|
| 154 |
``` cpp
|
|
|
|
| 159 |
The default argument for `U` is instantiated to form the type
|
| 160 |
`S<bool, int>*`.
|
| 161 |
|
| 162 |
— *end example*]
|
| 163 |
|
| 164 |
+
A *template-argument* followed by an ellipsis is a pack expansion
|
| 165 |
+
[[temp.variadic]].
|
| 166 |
|
| 167 |
### Template type arguments <a id="temp.arg.type">[[temp.arg.type]]</a>
|
| 168 |
|
| 169 |
A *template-argument* for a *template-parameter* which is a type shall
|
| 170 |
be a *type-id*.
|
|
|
|
| 190 |
}
|
| 191 |
```
|
| 192 |
|
| 193 |
— *end example*]
|
| 194 |
|
| 195 |
+
[*Note 1*: A template type argument may be an incomplete type
|
| 196 |
+
[[basic.types]]. — *end note*]
|
| 197 |
|
| 198 |
### Template non-type arguments <a id="temp.arg.nontype">[[temp.arg.nontype]]</a>
|
| 199 |
|
| 200 |
+
If the type `T` of a *template-parameter* [[temp.param]] contains a
|
| 201 |
+
placeholder type [[dcl.spec.auto]] or a placeholder for a deduced class
|
| 202 |
+
type [[dcl.type.class.deduct]], the type of the parameter is the type
|
| 203 |
+
deduced for the variable `x` in the invented declaration
|
| 204 |
+
|
| 205 |
+
``` cpp
|
| 206 |
+
T x = template-argument ;
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
If a deduced parameter type is not permitted for a *template-parameter*
|
| 210 |
+
declaration [[temp.param]], the program is ill-formed.
|
| 211 |
|
| 212 |
A *template-argument* for a non-type *template-parameter* shall be a
|
| 213 |
+
converted constant expression [[expr.const]] of the type of the
|
| 214 |
+
*template-parameter*.
|
|
|
|
|
|
|
| 215 |
|
| 216 |
+
[*Note 1*: If the *template-argument* is an overload set (or the
|
| 217 |
+
address of such, including forming a pointer-to-member), the matching
|
| 218 |
+
function is selected from the set [[over.over]]. — *end note*]
|
|
|
|
|
|
|
| 219 |
|
| 220 |
+
For a non-type *template-parameter* of reference or pointer type, or for
|
| 221 |
+
each non-static data member of reference or pointer type in a non-type
|
| 222 |
+
*template-parameter* of class type or subobject thereof, the reference
|
| 223 |
+
or pointer value shall not refer to or be the address of (respectively):
|
| 224 |
+
|
| 225 |
+
- a temporary object [[class.temporary]],
|
| 226 |
+
- a string literal object [[lex.string]],
|
| 227 |
+
- the result of a `typeid` expression [[expr.typeid]],
|
| 228 |
+
- a predefined `__func__` variable [[dcl.fct.def.general]], or
|
| 229 |
+
- a subobject [[intro.object]] of one of the above.
|
| 230 |
|
| 231 |
[*Example 1*:
|
| 232 |
|
| 233 |
``` cpp
|
| 234 |
template<const int* pci> struct X { ... };
|
|
|
|
| 250 |
template<void (*pf)(int)> struct A { ... };
|
| 251 |
|
| 252 |
A<&f> a; // selects f(int)
|
| 253 |
|
| 254 |
template<auto n> struct B { ... };
|
| 255 |
+
B<5> b1; // OK, template parameter type is int
|
| 256 |
+
B<'a'> b2; // OK, template parameter type is char
|
| 257 |
+
B<2.5> b3; // OK, template parameter type is double
|
| 258 |
+
B<void(0)> b4; // error: template parameter type cannot be void
|
| 259 |
```
|
| 260 |
|
| 261 |
— *end example*]
|
| 262 |
|
| 263 |
[*Note 2*:
|
| 264 |
|
| 265 |
+
A *string-literal* [[lex.string]] is not an acceptable
|
| 266 |
+
*template-argument* for a *template-parameter* of non-class type.
|
| 267 |
|
| 268 |
[*Example 2*:
|
| 269 |
|
| 270 |
``` cpp
|
| 271 |
+
template<class T, T p> class X {
|
| 272 |
...
|
| 273 |
};
|
| 274 |
|
| 275 |
+
X<const char*, "Studebaker"> x; // error: string literal object as template-argument
|
| 276 |
+
X<const char*, "Knope" + 1> x2; // error: subobject of string literal object as template-argument
|
| 277 |
|
| 278 |
const char p[] = "Vivisectionist";
|
| 279 |
+
X<const char*, p> y; // OK
|
| 280 |
+
|
| 281 |
+
struct A {
|
| 282 |
+
constexpr A(const char*) {}
|
| 283 |
+
};
|
| 284 |
+
|
| 285 |
+
X<A, "Pyrophoricity"> z; // OK, string-literal is a constructor argument to A
|
| 286 |
```
|
| 287 |
|
| 288 |
— *end example*]
|
| 289 |
|
| 290 |
— *end note*]
|
| 291 |
|
| 292 |
[*Note 3*:
|
| 293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
A temporary object is not an acceptable *template-argument* when the
|
| 295 |
corresponding *template-parameter* has reference type.
|
| 296 |
|
| 297 |
+
[*Example 3*:
|
| 298 |
|
| 299 |
``` cpp
|
| 300 |
template<const int& CRI> struct B { ... };
|
| 301 |
|
| 302 |
+
B<1> b1; // error: temporary would be required for template argument
|
| 303 |
|
| 304 |
int c = 1;
|
| 305 |
+
B<c> b2; // OK
|
| 306 |
+
|
| 307 |
+
struct X { int n; };
|
| 308 |
+
struct Y { const int &r; };
|
| 309 |
+
template<Y y> struct C { ... };
|
| 310 |
+
C<Y{X{1}.n}> c; // error: subobject of temporary object used to initialize
|
| 311 |
+
// reference member of template parameter
|
| 312 |
```
|
| 313 |
|
| 314 |
— *end example*]
|
| 315 |
|
| 316 |
— *end note*]
|
|
|
|
| 323 |
only primary class templates are considered when matching the template
|
| 324 |
template argument with the corresponding parameter; partial
|
| 325 |
specializations are not considered even if their parameter lists match
|
| 326 |
that of the template template parameter.
|
| 327 |
|
| 328 |
+
Any partial specializations [[temp.class.spec]] associated with the
|
| 329 |
primary class template or primary variable template are considered when
|
| 330 |
a specialization based on the template *template-parameter* is
|
| 331 |
instantiated. If a specialization is not visible at the point of
|
| 332 |
instantiation, and it would have been selected had it been visible, the
|
| 333 |
program is ill-formed, no diagnostic required.
|
|
|
|
| 350 |
```
|
| 351 |
|
| 352 |
— *end example*]
|
| 353 |
|
| 354 |
A *template-argument* matches a template *template-parameter* `P` when
|
| 355 |
+
`P` is at least as specialized as the *template-argument* `A`. In this
|
| 356 |
+
comparison, if `P` is unconstrained, the constraints on `A` are not
|
| 357 |
+
considered. If `P` contains a template parameter pack, then `A` also
|
| 358 |
+
matches `P` if each of `A`’s template parameters matches the
|
| 359 |
+
corresponding template parameter in the *template-head* of `P`. Two
|
| 360 |
+
template parameters match if they are of the same kind (type, non-type,
|
| 361 |
+
template), for non-type *template-parameter*s, their types are
|
| 362 |
+
equivalent [[temp.over.link]], and for template *template-parameter*s,
|
| 363 |
+
each of their corresponding *template-parameter*s matches, recursively.
|
| 364 |
+
When `P`’s *template-head* contains a template parameter pack
|
| 365 |
+
[[temp.variadic]], the template parameter pack will match zero or more
|
| 366 |
+
template parameters or template parameter packs in the *template-head*
|
| 367 |
+
of `A` with the same type and form as the template parameter pack in `P`
|
| 368 |
+
(ignoring whether those template parameters are template parameter
|
| 369 |
+
packs).
|
| 370 |
|
| 371 |
[*Example 2*:
|
| 372 |
|
| 373 |
``` cpp
|
| 374 |
template<class T> class A { ... };
|
|
|
|
| 411 |
eval<E<int, float>> eE; // error: E does not match TT in partial specialization
|
| 412 |
```
|
| 413 |
|
| 414 |
— *end example*]
|
| 415 |
|
| 416 |
+
[*Example 4*:
|
| 417 |
+
|
| 418 |
+
``` cpp
|
| 419 |
+
template<typename T> concept C = requires (T t) { t.f(); };
|
| 420 |
+
template<typename T> concept D = C<T> && requires (T t) { t.g(); };
|
| 421 |
+
|
| 422 |
+
template<template<C> class P> struct S { };
|
| 423 |
+
|
| 424 |
+
template<C> struct X { };
|
| 425 |
+
template<D> struct Y { };
|
| 426 |
+
template<typename T> struct Z { };
|
| 427 |
+
|
| 428 |
+
S<X> s1; // OK, X and P have equivalent constraints
|
| 429 |
+
S<Y> s2; // error: P is not at least as specialized as Y
|
| 430 |
+
S<Z> s3; // OK, P is at least as specialized as Z
|
| 431 |
+
```
|
| 432 |
+
|
| 433 |
+
— *end example*]
|
| 434 |
+
|
| 435 |
A template *template-parameter* `P` is at least as specialized as a
|
| 436 |
template *template-argument* `A` if, given the following rewrite to two
|
| 437 |
function templates, the function template corresponding to `P` is at
|
| 438 |
least as specialized as the function template corresponding to `A`
|
| 439 |
+
according to the partial ordering rules for function templates
|
| 440 |
+
[[temp.func.order]]. Given an invented class template `X` with the
|
| 441 |
+
*template-head* of `A` (including default arguments and
|
| 442 |
+
*requires-clause*, if any):
|
| 443 |
|
| 444 |
+
- Each of the two function templates has the same template parameters
|
| 445 |
+
and *requires-clause* (if any), respectively, as `P` or `A`.
|
| 446 |
- Each function template has a single function parameter whose type is a
|
| 447 |
specialization of `X` with template arguments corresponding to the
|
| 448 |
template parameters from the respective function template where, for
|
| 449 |
+
each template parameter `PP` in the *template-head* of the function
|
| 450 |
+
template, a corresponding template argument `AA` is formed. If `PP`
|
| 451 |
+
declares a template parameter pack, then `AA` is the pack expansion
|
| 452 |
+
`PP...` [[temp.variadic]]; otherwise, `AA` is the *id-expression*
|
| 453 |
`PP`.
|
| 454 |
|
| 455 |
If the rewrite produces an invalid type, then `P` is not at least as
|
| 456 |
specialized as `A`.
|
| 457 |
|