struct S { int i = 0; }; bool operator==(const S&, const S&) { return true; } int f() { S() != S(); // well-formed, yields false? }
struct S { int a[3]; }
acquire generated
comparison functions? If yes, what about int[3]
(i.e. an
array not wrapped in a struct)?struct A { }; void operator==(const A&, const A&); void operator==(const A&, int); void operator==(A&, const A&); void operator==(A&&, volatile A&); void operator==(const volatile A&&, const A&); void operator==(A, const A&); template<class T> void operator==(const T&, A); template<class T> void operator==(const T&, const T&); template<class T> void operator==(T&&, T&&);
struct A { int x, y; } a; namespace N { void *operator<(A, A); auto q = a > a; }What's the type of q? Is this example some flavor of ill-formed? Do we use N::operator<? Do we do a subobject comparison?
A type cv T supports comparison by subobject if T is an array type, or is a non-union class type that satisfies the following constraints:Change in 9 [class] paragraph 7 bullet 6:T supports operator op if overload resolution (13.3.1.2 [over.match.oper]) finds a viable function for the expression
- T has no virtual base class (clause 10 [class.derived]),
- T has no virtual member function (10.3 [class.virtual]),
- T has no direct mutable member (7.1.1 [dcl.stc]),
- T has no direct non-static data member of pointer type (9.2 [class.mem]), and
- T has no user-provided or deleted copy/move constructor or assignment operator (12.8 [class.copy]).
x op y
, where x and y are lvalues of type T.T supports equality comparison by subobject if T supports comparison by subobject and does not support operator== and operator!=.
T supports relational comparison by subobject if T supports equality comparison by subobject and does not support operator <, operator <=, operator >, and operator >=.
Change in 9.2 [class.mem] paragraph 1:
- ...
- has all non-static data members and bit-fields in the class and its base classes
first declared inas direct members of the same class, and- ...
The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere. A direct member of a class is a member of that class that was first declared within the class's member-specification. ...Add a new section 9.10 [class.oper]:
9.10 Operators [class.oper]Add a paragraph after 13.3.1.2 [over.match.oper] paragraph 7:[ Note: This section specifies the meaning of relational (5.9 [expr.rel]) or equality (5.10 [expr.eq]) operators applied to values of class or array type. ]
Comparing for equality two objects x and y that have the same class or array type T (ignoring cv-qualification) is defined as follows:
- A sequence of corresponding subobjects of x and y is formed by starting with a sequence comprising x corresponding to y, and repeatedly replacing each element whose type supports equality comparison by subobject (3.9.2 [basic.compound]) with a sequence of the corresponding subobjects of the direct base classes and direct members of that type, in order of declaration or order of increasing array subscript.
- For each element in the sequence of corresponding subobjects, the corresponding subobjects are compared using ==. If this comparison, when contextually converted to
bool
, yields false, no further subobjects are compared, andx == y
yields false andx != y
yields true. If all such comparisons yield true, thenx == y
yields true andx != y
yields false.Comparing two objects x and y that have the same class or array type T (ignoring cv-qualification) is defined as follows:
[ Example:
- For x > y, the result is y < x. For x >= y, the result is y <= x.
- A sequence of corresponding subobjects of x and y is formed by starting with a sequence comprising x corresponding to y, and repeatedly replacing each element whose type supports relational comparison by subobject (3.9.2 [basic.compound]) with a sequence of the corresponding subobjects of the direct base classes and direct members of that type, in order of declaration or order of increasing array subscript.
- For each element in the sequence of corresponding subobjects, the corresponding subobjects are compared using ==. If this comparison, when contextually converted to bool, yields false for the first time, that element is the first differing one. If the final element is reached for a < comparison, that element is the first differing one, and is not compared with ==. Otherwise, if all such comparisons yield true, there is no first differing element.
- If there is no first differing element, the result of the <= comparison is true. Otherwise, the corresponding subobjects of the first differing element are compared using <. The result of this comparison, when contextually converted to bool, is the result of the overall comparison.
struct B { int i = 0; }; struct S : B { int j = 1; }; struct T : S { bool operator>(T) = delete; }; void f() { B b; S s1, s2; s2.j = 2; s1 == s1; // yields true s1 != s2; // yields true s1 < s1; // yields false s1 < s2; // yields true s1 == b; // error: not the same class type T() == T(); // yields true T() < T(); // error: operator> is user-declared }-- end example ]
If overload resolution yields no viable function (13.3.2 [over.match.viable]) for a relational (5.9 [expr.rel]) or equality (5.10 [expr.eq]) operator and the operands are of the same class or array type T (ignoring cv-qualification), then:
- If the operator is == and T does not support equality comparison by subobject, the program is ill-formed.
- If the operator is < and T does not support relational comparison by subobject, the program is ill-formed.
- If overload resolution for the operator would yield a viable function in any translation unit, the program is ill-formed, no diagnostic required.
- Otherwise, the operator is treated as a built-in operator and interpreted according to 9.10 [class.oper].