<html>
<head>
<title>N4532: Proposed wording for default comparisons</title>

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .new { text-decoration:none; font-weight:bold; background-color:#D0FFD0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }  
  strong { font-weight: inherit; color: #2020ff }
</style>
</head>

<body>
N4532<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
2015-05-22<br/>

<h1>N4532: Proposed wording for default comparisons</h1>

<h2>Introduction</h2>

This paper presents proposed wording to implement defaulted
comparisons as presented in N4475 "Default comparisons (R2)" by Bjarne
Stroustrup.

<h2>Open Issues</h2>

<ul>

<li>It seems natural to generate != from == even if the class doesn't
satisfy the constraints.  This would only be possible if a
user-defined operator== exists, of course.  Same for the relational
operators other than &lt;.  Is that the intent (deviating from N4475,
top of page 17)?  Example:

<pre>
  struct S {
    int i = 0;
  };
  bool operator==(const S&, const S&)
  { return true; }

  int f() {
    S() != S();    // well-formed, yields false?
  }
</pre>

</li>

<li>A class with a mutable member does not get a memberwise operator==
or operator&lt; (deviating from N4475 page 17).</li>

<li>Should <code>struct S { int a[3]; }</code> acquire generated
comparison functions?  If yes, what about <code>int[3]</code> (i.e. an
array not wrapped in a struct)?</li>

<li>Generation of memberwise operator&lt; relies on memberwise
operator==.  Should we generate operator&lt; for a class C (implicitly
using memberwise == in its definition) even if we have a user-declared
operator== for C, indicating that memberwise == is not desired?</li>

<li>What exactly does it mean that "a class has a given operator
declared"?  The operators in question are binary, may be free
functions, and may be function templates.  Examples:

<pre>
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&lt;class T>
void operator==(const T&, A);
template&lt;class T>
void operator==(const T&, const T&);
template&lt;class T>
void operator==(T&&, T&&);
</pre>
</li>

<li>What kind of lookup is performed for the operator function name
when determining that "a class has a given operator declared"?  Usual
unqualified lookup from which context? Just argument-dependent lookup?
Something else?  Example:
<pre>
struct A { int x, y; } a;
namespace N {
  void *operator&lt;(A, A);
  auto q = a > a;
}
</pre>

What's the type of q? Is this example some flavor of ill-formed? Do we
use N::operator&lt;? Do we do a subobject comparison?</li>


</ul>


<h2>Wording</h2>

Add at the end of 3.9.2 [basic.compound]:

<blockquote class="new">
A type <em>cv</em> T <em>supports comparison by subobject</em>
if T is an array type,
or is a non-union class type that satisfies the following constraints:

<ul>

<li>T has no virtual base class (clause 10 [class.derived]),</li>
<li>T has no virtual member function (10.3 [class.virtual]),</li>
<li>T has no direct mutable member (7.1.1 [dcl.stc]),</li>

<li>T has no direct non-static data member of pointer type (9.2
[class.mem]), and</li>

<li>T has no user-provided or deleted copy/move constructor or
assignment operator (12.8 [class.copy]).</li>

</ul>

T <em>supports operator op</em> if overload resolution (13.3.1.2
[over.match.oper]) finds a viable function for the expression <code>x
<em>op</em> y</code>, where x and y are lvalues of type T.

<p>

T <em>supports equality comparison by subobject</em> if T supports
comparison by subobject and does not support operator== and operator!=.

<p>

T <em>supports relational comparison by subobject</em> if T supports
equality comparison by subobject and does not support operator &lt;,
operator &lt;=, operator &gt;, and operator &gt;=.

</blockquote>


Change in 9 [class] paragraph 7 bullet 6:

<blockquote>
<ul>
<li>...</li>

<li>has all non-static data members and bit-fields in the class and
its base classes <del>first declared in</del> <ins>as direct members
of</ins> the same class, and</li>

<li>...</li>

</ul>

</blockquote>

Change in 9.2 [class.mem] paragraph 1:

<blockquote>
The <em>member-specification</em> in a class definition declares the
full set of members of the class; no member can be added elsewhere.  <ins>A <em>direct
member</em> of a class is a member of that class that was first
declared within the class's <em>member-specification</em>.</ins> ...

</blockquote>

Add a new section 9.10 [class.oper]:

<blockquote class="new">
<b>9.10 Operators [class.oper]</b>
<p>

[ 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. ]

<p>
Comparing for equality two objects x and y that have the same class or
array type T (ignoring cv-qualification) is defined as follows:

<ul>

<li>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.</li>

<li>For each element in the sequence of corresponding subobjects, the
corresponding subobjects are compared using ==. If this comparison,
when contextually converted to <code>bool</code>, yields false, no
further subobjects are compared, and <code>x == y</code> yields false
and <code>x != y</code> yields true.  If all such comparisons yield
true, then <code>x == y</code> yields true and <code>x != y</code>
yields false.</li>

</ul>

<p>
Comparing two objects x and y that have the same class or array type T (ignoring cv-qualification) is defined as follows:

<ul>
<li>For x &gt; y, the result is y &lt; x.  For x &gt;= y, the result
is y &lt;= x.</li>

<li>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.</li>

<li>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 &lt; 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.</li>

<li>If there is no first differing element, the result of the &lt;=
comparison is true. Otherwise, the corresponding subobjects of the
first differing element are compared using &lt;. The result of this
comparison, when contextually converted to bool, is the result of
the overall comparison.</li>

</ul>

[ Example:
<pre>
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 &lt; s1;       // yields false
  s1 &lt; s2;       // yields true
  s1 == b;       // error: not the same class type
  T() == T();    // yields true
  T() &lt; T();     // error: operator> is user-declared
}
</pre>
-- end example ]

</blockquote>


Add a paragraph after 13.3.1.2 [over.match.oper] paragraph 7:

<blockquote class="new">

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:

<ul>
<li>If the operator is == and T does not support equality comparison
by subobject, the program is ill-formed.</li>

<li>If the operator is &lt; and T does not support relational comparison by subobject, the program is ill-formed.

<li>If overload resolution for the operator would yield a viable
function in any translation unit, the program is ill-formed, no
diagnostic required.</li>

<li>Otherwise, the operator is treated as a built-in
operator and interpreted according to 9.10 [class.oper].</li>

</blockquote>

<h2>Acknowledgements</h2>

Thanks to Richard Smith for valuable input, and the majority of the
drafting presented above.  All errors are mine, of course.  Thanks to
Oleg Smolsky for acquiring a paper number and some discussions on
earlier wording.

</body>
</html>
