An expression is *equality preserving* if, given equal inputs, the expression results in
equal outputs. The inputs to an expression are the set of the expression's operands. The
output of an expression is the expression's result and all operands modified by the expression.

Not all input values must be valid for a given expression; e.g., for integers a
and b, the expression a / b is not well-defined when b is 0. This
does not preclude the expression a / b being equality preserving. The
*domain* of an expression is the set of input values for which the
expression is required to be well-defined.

Expressions required by this specification to be equality preserving are
further required to be stable: two evaluations of such an expression with the same
input objects must have equal outputs absent any
explicit intervening modification of those input objects.
[ *Note:* This requirement allows generic code to reason
about the current values of objects based on knowledge of the prior values as
observed via equality preserving expressions. It effectively forbids spontaneous
changes to an object, changes to an object from another thread of execution, changes
to an object as side effects of non-modifying expressions, and changes to an object as
side effects of modifying a distinct object if those changes could be observable
to a library function via an equality preserving expression that is required to be
valid for that object. * — end note* ]

Expressions declared in a requires-expression in this document are required to be equality preserving, except for those annotated with the comment “not required to be equality preserving.” An expression so annotated may be equality preserving, but is not required to be so.

An expression that may alter the value of one or more of its inputs in a manner observable to equality preserving expressions is said to modify those inputs. This document uses a notational convention to specify which expressions declared in a requires-expression modify which inputs: except where otherwise specified, an expression operand that is a non-constant lvalue or rvalue may be modified. Operands that are constant lvalues or rvalues must not be modified.

Where a requires-expression declares an expression that is non-modifying
for some constant lvalue operand, additional variations of that expression that accept
a non-constant lvalue or (possibly constant) rvalue for the given operand are also
required except where such an expression variation is explicitly required with
differing semantics. These *implicit expression variations* must meet the semantic
requirements of the declared expression. The extent to which an implementation
validates the syntax of the variations is unspecified.

[ *Example:*

template <class T> concept bool C = requires(T a, T b, const T c, const T d) { c == d; // #1 a = std::move(b); // #2 a = c; // #3 };

Expression #1 does not modify either of its operands, #2 modifies both of its operands, and #3 modifies only its first operand a.

Expression #1 implicitly requires additional expression variations that meet the requirements for c == d (including non-modification), as if the expressions

a == d; a == b; a == move(b); a == d; c == a; c == move(a); c == move(d); move(a) == d; move(a) == b; move(a) == move(b); move(a) == move(d); move(c) == b; move(c) == move(b); move(c) == d; move(c) == move(d);

had been declared as well.

Expression #3 implicitly requires additional expression variations that meet the
requirements for a = c (including non-modification of the second operand),
as if the expressions a = b and a = move(c) had been declared.
Expression #3 does not implicitly require an expression variation with a
non-constant rvalue second operand, since expression #2 already specifies exactly
such an expression explicitly.
* — end example* ]

[ *Example:*
The following type T meets the explicitly stated syntactic requirements
of concept C above but does not meet the additional implicit requirements:

struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };

T fails to meet the implicit
requirements of C, so C<T> is not satisfied. Since
implementations are not required to validate the syntax of implicit requirements, it
is unspecified whether or not an implementation diagnoses as ill-formed a program
which requires C<T>.
* — end example* ]