[temp.constr.op]

# 13 Templates [[temp]](./#temp)

## 13.5 Template constraints [[temp.constr]](temp.constr#op)

### 13.5.2 Constraints [[temp.constr.constr]](temp.constr.constr#temp.constr.op)

#### 13.5.2.2 Logical operations [temp.constr.op]

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1640)

There are two binary logical operations on constraints: conjunction
and disjunction[.](#1.sentence-1)

[*Note [1](#note-1)*:

These logical operations have no corresponding C++ syntax[.](#1.sentence-2)

For the purpose of exposition, conjunction is spelled
using the symbol  â§  and disjunction is spelled using the
symbol  â¨ [.](#1.sentence-3)

The operands of these operations are called the left
and right operands[.](#1.sentence-4)

In the constraint A â§ B,A is the left operand, and B is the right operand[.](#1.sentence-5)

â *end note*]

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1653)

A [*conjunction*](#def:conjunction "13.5.2.2 Logical operations [temp.constr.op]") is a constraint taking two
operands[.](#2.sentence-1)

To determine if a conjunction is[*satisfied*](#def:constraint,satisfaction,conjunction "13.5.2.2 Logical operations [temp.constr.op]"),
the satisfaction of
the first operand is checked[.](#2.sentence-2)

If that is not satisfied, the conjunction is not satisfied[.](#2.sentence-3)

Otherwise, the conjunction is satisfied if and only if the second
operand is satisfied[.](#2.sentence-4)

[3](#3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1664)

A [*disjunction*](#def:disjunction "13.5.2.2 Logical operations [temp.constr.op]") is a constraint taking two
operands[.](#3.sentence-1)

To determine if a disjunction is[*satisfied*](#def:constraint,satisfaction,disjunction "13.5.2.2 Logical operations [temp.constr.op]"),
the satisfaction of
the first operand is checked[.](#3.sentence-2)

If that is satisfied, the disjunction is satisfied[.](#3.sentence-3)

Otherwise, the disjunction is satisfied if and only if the second
operand is satisfied[.](#3.sentence-4)

[4](#4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1676)

[*Example [1](#example-1)*: template<typename T>constexpr bool get_value() { return T::value; }template<typename T>requires (sizeof(T) > 1) && (get_value<T>())void f(T); // has associated constraint sizeof(T) > 1  â§  get_value<T>()void f(int);

f('a'); // OK, calls f(int)

In the satisfaction of the [associated constraints](temp.constr.decl#def:associated_constraints "13.5.3 Constrained declarations [temp.constr.decl]") of f, the constraint sizeof(char) > 1 is not satisfied;
the second operand is not checked for satisfaction[.](#4.sentence-1)

â *end example*]

[5](#5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/templates.tex#L1695)

[*Note [2](#note-2)*:

A logical negation expression ([[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")) is an atomic constraint;
the negation operator is not treated as a logical operation on constraints[.](#5.sentence-1)

As a result, distinct negation [*constraint-expression*](temp.constr.decl#nt:constraint-expression "13.5.3 Constrained declarations [temp.constr.decl]")*s* that are equivalent under [[temp.over.link]](temp.over.link "13.7.7.2 Function template overloading") do not subsume one another under [[temp.constr.order]](temp.constr.order "13.5.5 Partial ordering by constraints")[.](#5.sentence-2)

Furthermore, if substitution to determine
whether an atomic constraint is satisfied ([[temp.constr.atomic]](temp.constr.atomic "13.5.2.3 Atomic constraints"))
encounters a substitution failure, the constraint is not satisfied,
regardless of the presence of a negation operator[.](#5.sentence-3)

[*Example [2](#example-2)*: template <class T> concept sad = false;

template <class T> int f1(T) requires (!sad<T>);template <class T> int f1(T) requires (!sad<T>) && true;int i1 = f1(42); // ambiguous, !sad<T> atomic constraint expressions ([[temp.constr.atomic]](temp.constr.atomic "13.5.2.3 Atomic constraints"))// are not formed from the same [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]")template <class T> concept not_sad = !sad<T>;template <class T> int f2(T) requires not_sad<T>;template <class T> int f2(T) requires not_sad<T> && true;int i2 = f2(42); // OK, !sad<T> atomic constraint expressions both come from not_sadtemplate <class T> int f3(T) requires (!sad<typename T::type>);int i3 = f3(42); // error: associated constraints not satisfied due to substitution failuretemplate <class T> concept sad_nested_type = sad<typename T::type>;template <class T> int f4(T) requires (!sad_nested_type<T>);int i4 = f4(42); // OK, substitution failure contained within sad_nested_type

Here,requires (!sad<typename T​::​type>) requires
that there is a nested type that is not sad,
whereasrequires (!sad_nested_type<T>) requires
that there is no sad nested type[.](#5.sentence-4)

â *end example*]

â *end note*]
