[concepts.equality] # 18 Concepts library [[concepts]](./#concepts) ## 18.2 Equality preservation [concepts.equality] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L27) An expression is [*equality-preserving*](#def:expression,equality-preserving "18.2 Equality preservation [concepts.equality]") if, given equal inputs, the expression results in equal outputs[.](#1.sentence-1) The inputs to an expression are the set of the expression's operands[.](#1.sentence-2) The output of an expression is the expression's result and all operands modified by the expression[.](#1.sentence-3) For the purposes of this subclause, the operands of an expression are the largest subexpressions that include only: - [(1.1)](#1.1) an [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") ([[expr.prim.id]](expr.prim.id "7.5.5 Names")), and - [(1.2)](#1.2) invocations of the library function templatesstd​::​move,std​::​forward, andstd​::​declval ([[forward]](forward "22.2.4 Forward/move helpers"), [[declval]](declval "22.2.6 Function template declval"))[.](#1.sentence-4) [*Example [1](#example-1)*: The operands of the expression a = std​::​move(b) area and std​::​move(b)[.](#1.sentence-5) — *end example*] [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L48) Not all input values need be valid for a given expression[.](#2.sentence-1) [*Example [2](#example-2)*: For integers a and b, the expression a / b is not well-defined when b is 0[.](#2.sentence-2) This does not preclude the expression a / b being equality-preserving[.](#2.sentence-3) — *end example*] The [*domain*](#def:expression,domain "18.2 Equality preservation [concepts.equality]") of an expression is the set of input values for which the expression is required to be well-defined[.](#2.sentence-4) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L59) Expressions required to be equality-preserving are further required to be stable: two evaluations of such an expression with the same input objects are required to have equal outputs absent any explicit intervening modification of those input objects[.](#3.sentence-1) [*Note [1](#note-1)*: 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[.](#3.sentence-2) 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[.](#3.sentence-3) — *end note*] [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L75) Expressions declared in a [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") in the library clauses are required to be equality-preserving, except for those annotated with the comment “not required to be equality-preserving[.](#4.sentence-1)” An expression so annotated may be equality-preserving, but is not required to be so[.](#4.sentence-2) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L81) 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[.](#5.sentence-1) The library clauses use a notational convention to specify which expressions declared in a [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") modify which inputs: except where otherwise specified, an expression operand that is a non-constant lvalue or rvalue may be modified[.](#5.sentence-2) Operands that are constant lvalues or rvalues are required to not be modified[.](#5.sentence-3) For the purposes of this subclause, the cv-qualification and value category of each operand are determined by assuming that each template type parameter denotes a cv-unqualified complete non-array object type[.](#5.sentence-4) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L95) Where a [*requires-expression*](expr.prim.req.general#nt:requires-expression "7.5.8.1 General [expr.prim.req.general]") 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[.](#6.sentence-1) These[*implicit expression variations*](#def:implicit_expression_variations) are required to meet the semantic requirements of the declared expression[.](#6.sentence-2) The extent to which an implementation validates the syntax of the variations is unspecified[.](#6.sentence-3) [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L105) [*Example [3](#example-3)*: template concept C = requires(T a, T b, const T c, const T d) { c == d; // #1 a = std::move(b); // #2 a = c; // #3}; For the above example: - [(7.1)](#7.1) Expression #1 does not modify either of its operands, #2 modifies both of its operands, and #3 modifies only its first operand a[.](#7.1.sentence-1) - [(7.2)](#7.2) Expression #1 implicitly requires additional expression variations that meet the requirements for c == d (including non-modification), as if the expressions c == b; c == std::move(d); c == std::move(b); std::move(c) == d; std::move(c) == b; std::move(c) == std::move(d); std::move(c) == std::move(b); a== d; a == b; a == std::move(d); a == std::move(b); std::move(a) == d; std::move(a) == b; std::move(a) == std::move(d); std::move(a) == std::move(b); had been declared as well[.](#7.2.sentence-1) - [(7.3)](#7.3) 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 = std​::​move(c) had been declared[.](#7.3.sentence-1) 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[.](#7.3.sentence-2) — *end example*] [8](#8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L148) [*Example [4](#example-4)*: 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 T satisfies but does not model C[.](#8.sentence-2) Since implementations are not required to validate the syntax of implicit requirements, it is unspecified whether an implementation diagnoses as ill-formed a program that requires C[.](#8.sentence-3) — *end example*]