Files
2025-10-25 03:02:53 +03:00

185 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.2Equality 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.1General[expr.prim.id.general]") ([[expr.prim.id]](expr.prim.id "7.5.5Names")), and
- [(1.2)](#1.2)
invocations of the library function templatesstd::move,std::forward, andstd::declval ([[forward]](forward "22.2.4Forward/move helpers"), [[declval]](declval "22.2.6Function 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.2Equality 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.1General[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.1General[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.1General[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<class T> 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<T>[.](#8.sentence-3)
— *end example*]