tmp/tmpwt3stmeq/{from.md → to.md}
RENAMED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#### Logical operations <a id="temp.constr.op">[[temp.constr.op]]</a>
|
| 2 |
+
|
| 3 |
+
There are two binary logical operations on constraints: conjunction and
|
| 4 |
+
disjunction.
|
| 5 |
+
|
| 6 |
+
[*Note 1*: These logical operations have no corresponding C++ syntax.
|
| 7 |
+
For the purpose of exposition, conjunction is spelled using the symbol ∧
|
| 8 |
+
and disjunction is spelled using the symbol ∨. The operands of these
|
| 9 |
+
operations are called the left and right operands. In the constraint
|
| 10 |
+
A ∧ B, A is the left operand, and B is the right operand. — *end note*]
|
| 11 |
+
|
| 12 |
+
A *conjunction* is a constraint taking two operands. To determine if a
|
| 13 |
+
conjunction is *satisfied*, the satisfaction of the first operand is
|
| 14 |
+
checked. If that is not satisfied, the conjunction is not satisfied.
|
| 15 |
+
Otherwise, the conjunction is satisfied if and only if the second
|
| 16 |
+
operand is satisfied.
|
| 17 |
+
|
| 18 |
+
A *disjunction* is a constraint taking two operands. To determine if a
|
| 19 |
+
disjunction is *satisfied*, the satisfaction of the first operand is
|
| 20 |
+
checked. If that is satisfied, the disjunction is satisfied. Otherwise,
|
| 21 |
+
the disjunction is satisfied if and only if the second operand is
|
| 22 |
+
satisfied.
|
| 23 |
+
|
| 24 |
+
[*Example 1*:
|
| 25 |
+
|
| 26 |
+
``` cpp
|
| 27 |
+
template<typename T>
|
| 28 |
+
constexpr bool get_value() { return T::value; }
|
| 29 |
+
|
| 30 |
+
template<typename T>
|
| 31 |
+
requires (sizeof(T) > 1) && (get_value<T>())
|
| 32 |
+
void f(T); // has associated constraint sizeof(T) > 1 ∧ get_value<T>()
|
| 33 |
+
|
| 34 |
+
void f(int);
|
| 35 |
+
|
| 36 |
+
f('a'); // OK: calls f(int)
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
In the satisfaction of the associated constraints [[temp.constr.decl]]
|
| 40 |
+
of `f`, the constraint `sizeof(char) > 1` is not satisfied; the second
|
| 41 |
+
operand is not checked for satisfaction.
|
| 42 |
+
|
| 43 |
+
— *end example*]
|
| 44 |
+
|
| 45 |
+
[*Note 2*:
|
| 46 |
+
|
| 47 |
+
A logical negation expression [[expr.unary.op]] is an atomic constraint;
|
| 48 |
+
the negation operator is not treated as a logical operation on
|
| 49 |
+
constraints. As a result, distinct negation *constraint-expression*s
|
| 50 |
+
that are equivalent under [[temp.over.link]] do not subsume one another
|
| 51 |
+
under [[temp.constr.order]]. Furthermore, if substitution to determine
|
| 52 |
+
whether an atomic constraint is satisfied [[temp.constr.atomic]]
|
| 53 |
+
encounters a substitution failure, the constraint is not satisfied,
|
| 54 |
+
regardless of the presence of a negation operator.
|
| 55 |
+
|
| 56 |
+
[*Example 2*:
|
| 57 |
+
|
| 58 |
+
``` cpp
|
| 59 |
+
template <class T> concept sad = false;
|
| 60 |
+
|
| 61 |
+
template <class T> int f1(T) requires (!sad<T>);
|
| 62 |
+
template <class T> int f1(T) requires (!sad<T>) && true;
|
| 63 |
+
int i1 = f1(42); // ambiguous, !sad<T> atomic constraint expressions[temp.constr.atomic]
|
| 64 |
+
// are not formed from the same expression
|
| 65 |
+
|
| 66 |
+
template <class T> concept not_sad = !sad<T>;
|
| 67 |
+
template <class T> int f2(T) requires not_sad<T>;
|
| 68 |
+
template <class T> int f2(T) requires not_sad<T> && true;
|
| 69 |
+
int i2 = f2(42); // OK, !sad<T> atomic constraint expressions both come from not_sad
|
| 70 |
+
|
| 71 |
+
template <class T> int f3(T) requires (!sad<typename T::type>);
|
| 72 |
+
int i3 = f3(42); // error: associated constraints not satisfied due to substitution failure
|
| 73 |
+
|
| 74 |
+
template <class T> concept sad_nested_type = sad<typename T::type>;
|
| 75 |
+
template <class T> int f4(T) requires (!sad_nested_type<T>);
|
| 76 |
+
int i4 = f4(42); // OK, substitution failure contained within sad_nested_type
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
Here, `requires (!sad<typename T::type>)` requires that there is a
|
| 80 |
+
nested `type` that is not `sad`, whereas
|
| 81 |
+
`requires (!sad_nested_type<T>)` requires that there is no `sad` nested
|
| 82 |
+
`type`.
|
| 83 |
+
|
| 84 |
+
— *end example*]
|
| 85 |
+
|
| 86 |
+
— *end note*]
|
| 87 |
+
|