<html>
<head>
<title>P1907R1: Inconsistencies with non-type template parameters</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 }
  table, td, th { border: 1px solid black; border-collapse:collapse; padding: 5px }
</style>
</head>

<body>
ISO/IEC JTC1 SC22 WG21 P1907R1<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Target audience: EWG, CWG<br/>
2019-11-08<br/>

<h1>P1907R1: Inconsistencies with non-type template parameters</h1>

<h2>Introduction</h2>

Non-type template parameters were originally limited to having scalar
non-floating-point types.

Through a number of recent changes, non-type template parameters of
class type are now supported as well, provided they have strong
structural equality, in particular no user-defined operator== for any
of the class's subobjects.

<ul>
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf">P0732R2</a> Class Types in Non-Type Template Parameters</li>

<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r2.html">P1185R2</a> &lt;=> != ==</li>

<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1630r1.html">P1630R1</a> Spaceship needs a tune-up, Addressing some discovered issues with P0515 and P1185</li>
</ul>

<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1714r1.html">P1714R1</a> (NTTP are incomplete without float, double, and long double!),
which added floating-point types as permissible non-type template parameters
(with bit-wise comparison on the value representation),
was rejected by plenary straw poll in Cologne.
<p>
The following wording implements guidance by EWG in Belfast to address
the following NB comments:

<ul>

  <li>US092 11.10.01 [class.compare.default] p04.2.1 Array members should have strong structural equality</li>
  <li>US093 11.10.01 p4 Move definition of "strong structural equality" near its use in</li>
  <li>(rejected) US094 11.10.01 p4 Deleted operator== should prevent strong structural equality</li>
  <li>US100 13.01 p4.1 Reference types should not have strong structural equality</li>
  <li>US102 13.1 p4.1 Allow non-type template parameters of floating-point type P1714</li>
  <li>US114 13.05 p1.5 Class types as non-type template arguments</li>
</ul>


<h2>Changes</h2>

<ul>
  <li>P1907R0: Presentations of inconsistencies (not repeated here)</li>
</ul>


<h2>Wording</h2>

Remove 11.11.1 [class.compare.default] paragraph 4:

<blockquote>
  <del>A type C has strong structural equality if, given a glvalue x of type const C, either:</del>
  <ul
    <li><del>C is a non-class type and x <=> x is a valid expression of type std::strong_ordering or std::strong_-
     equality, or</del></li>
    <li><del>C is a class type where all of the following hold:</del></li>
    <ul>
      <li><del>All of C’s base class subobjects and non-static data members have strong structural equality.</del></li>
       <li><del>C has no mutable or volatile non-static data members.</del></li>
       <li><del>At the end of the definition of C, overload resolution performed for the expression x == x succeeds
          and finds either a friend or public member == operator that is defined as defaulted in the definition
         of C.</del></li>
    </ul>
</li>
</ul>

</blockquote>

Change in 13.2 [temp.param] paragraph 4:

<blockquote>
  A non-type <em>template-parameter</em> shall have one of the following (optionally cv-qualified) types:
  <ul>
    <li><del>a literal type that has strong structural equality (11.11.1),</del></li>
    <li><del>an lvalue reference type,</del></li>
    <li><ins>a structural type (see below),</ins></li>
    <li>a type that contains a placeholder type (9.2.8.5), or</li>
    <li>a placeholder for a deduced class type (9.2.8.6).</li>
    </ul>
<del>[Note: Other types are disallowed either explicitly below or
implicitly by the rules governing the form of template-arguments (13.4
[temp.arg]). — end note]</del> The top-level cv-qualifiers on
the <em>template-parameter</em> are ignored when determining its type.
</blockquote>

Change in 13.4.2 [temp.arg.nontype] paragraph 2:

<blockquote>
A template-argument for a non-type template-parameter shall be a
converted constant expression (7.7) of the type of the
template-parameter . For a non-type template-parameter of reference or
pointer type, or for each non-static data member of reference or
pointer type in a non-type template-parameter of class type or
subobject thereof, the reference or pointer value shall not refer to
or be the address of (respectively):
<ul>
  <li><del>a subobject (6.7.2),</del></li>
  <li>a temporary object (6.7.7),</li>
  <li>a string literal (5.13.5),</li>
  <li>the result of a typeid expression (7.6.1.7), <del>or</del></li>
  <li>a predefined __func__ variable (9.5.1)<del>.</del><ins>, or</li>
  <li><ins>a subobject (6.7.2) of one of the above.</ins></li>
</ul>

</blockquote>

<blockquote class="new">
A <em>structural type</em> is one of the following:
<ul>
  <li>a scalar type, or</li>
  <li>an lvalue reference type, or</li>
  <li>a literal class type with the following properties:
    <ul>
      <li>all base classes and non-static data members are public and non-mutable and</li>
      <li>the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.</li>
</ul>
</blockquote>

Change in 13.2 [temp.param] paragraph 6:

<blockquote>
An <em>id-expression</em> naming a non-type template-parameter of
class type T denotes a static storage duration object of type const T,
known as a <em>template parameter object</em>, whose value is that of
the corresponding template argument after it has been converted to the
type of the template-parameter. All such template parameters in the
program of the same type with the same value denote the same template
parameter object. <ins>A template parameter object shall have constant
destruction (7.7 [expr.const]).</ins> [Note: If an id-expression names
a non-type non-reference template-parameter, then it is a prvalue if
it has non-class type.  Otherwise, if it is of class type T, it is an
lvalue and has type const T (7.5.4.1). — end note] [Example:

</blockquote>

Change in 13.6 [temp.type] paragraph 1:

<blockquote>
Two <em>template-id</em>s refer to the same class, function, or variable if
<ul>  
  <li>their <em>template-name</em>s, <em>operator-function-id</em>s, or <em>literal-operator-id</em>s refer to the same template and</li>
  <li>their corresponding type <em>template-argument</em>s are the same type and</li>
  <li><del>their corresponding non-type <em>template-argument</em>s of pointer-to-member type refer to the same class
     member or are both the null member pointer value and</del></li>
  <li><del>their corresponding non-type <em>template-argument</em>s of reference type refer to the same object or function
     and</del></li>
  <li>their <del>remaining</del> corresponding non-type <em>template-argument</em>s <del>have the same type and value</del> <ins>are template-argument-equivalent (see below)</ins> after conversion to the type of the <em>template-parameter</em><del>, where they are considered to have the same value if they
     compare equal with the == operator (7.6.10)</del>, and</li>
  <li>their corresponding template <em>template-argument</em>s refer to the same template.</li>
</blockquote>

<blockquote class="new">
Two values are <em>template-argument-equivalent</em>
if they are of the same type and

<ul class="new">
  <li>they are of integral type and their values are the same, or</li>
  <li>they are of floating-point type and their values are identical, or</li>
  <li>they are of type <code>std::nullptr_t</code>, or</li>
  <li>they are of enumeration type <code>T</code> and their values are the same [ Footnote: The identity of enumerators is not preserved. ],
    or</li>
  <li>they are of pointer type and they have the same pointer value, or</li>
  <li>they are of pointer-to-member type and they refer to the
  same class member or are both the null member pointer value, or</li>
  <li>they are of reference type and they refer to the same
    object or function, or</li>
  <li>they are of array type and their corresponding elements are
    template-argument-equivalent[ Footnote: An array as a <em>template-parameter</em> decays to a pointer. ], or</li>
  <li>they are of union type and either they both have no active member or they have the same active member and their active members are template-argument-equivalent, or</li>
  <li>they are of class type and their corresponding
    direct subobjects and reference members are template-argument-equivalent.
  </li>
</ul>
</blockquote>

</body>
</html>

