﻿<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

<style type="text/css">

body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

blockquote pre em { font-family: normal }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }

</style>

<title>Allow constant evaluation for all non-type template arguments</title>
</head>
<body>

<div style="text-align: right; float: right">
<p>
ISO/IEC JTC1 SC22 WG21<br>
N4198<br>
Richard Smith<br>
richard@metafoo.co.uk<br>
2014-10-06
</div>

<h1>Allow constant evaluation for all non-type template arguments</h1>

<h2><a name="Motivation">Motivation</a></h2>

<p>C++ supports the following kinds of non-type template parameters
and non-type template arguments (see [temp.param]/4 and [temp.arg.nontype]/1,5):

<table>
<tr><th>Parameter type</th><th>Argument syntax</th></tr>
<tr><td>Integral or enumeration</td>
    <td>Arbitrary constant expression</td></tr>
<tr><td>Pointer type</td>
    <td>Exact syntax <tt>&entity</tt>, <tt>array</tt>, <tt>function</tt>,<br/>
        referring to a static storage duration object or function with linkage, or<br/>
        arbitrary constant expression that evaluates to a null pointer</td>
<tr><td>Reference type</td>
    <td>Exact syntax <tt>object</tt>, <tt>function</tt>,<br/>
        referring to a static storage duration object or function with linkage</td>
<tr><td>Pointer to member</td>
    <td>Exact syntax <tt>&X::y</tt>, or<br/>
        arbitrary constant expression that evaluates to a null pointer-to-member</td>
<tr><td><tt>std::nullptr_t</tt></td>
    <td>Arbitrary constant expression</td></tr>
</table>

<p>The syntactic restrictions for pointers, references, and pointers to members
are awkward and prevent reasonable refactorings. For instance:

<pre class="extract">
template&lt;int *p> struct A {};
int n;
A&lt;&n> a; // ok

constexpr int *p() { return &amp;n; }
A&lt;p()> b; // error
</pre>

<p>The same refactorings work fine for integral types. They also work fine if
the template argument happens to evaluate to a null pointer:

<pre class="extract">
constexpr int *q() { return nullptr; }
A&lt;q()> c; // ok!
</pre>

<p>The historical reason for the restriction was most likely that C++
previously did not have a sufficiently strong specification for constant
expressions of pointer, reference, or pointer-to-member type. However, that is
no longer the case. The status quo is that an implementation is required to
evaluate such a template argument, but must then discard the result if it turns
out to not be null.

<p>In addition to the above, the restriction to entities with linkage is an
artifact of exported templates, and could have been removed when the linkage
restrictions on template type parameters were removed.

<p>This paper proposes revising the above table as follows:

<table>
<tr><th>Parameter type</th><th>Argument syntax</th></tr>
<tr><td>Integral or enumeration</td>
    <td>Arbitrary constant expression</td></tr>
<tr><td>Pointer type</td>
    <td>Arbitrary constant expression that evaluates to the address of a
        complete object with static storage duration, a function, or a null
        pointer</td>
<tr><td>Reference type</td>
    <td>Arbitrary constant expression that evaluates to a glvalue referring to a
        complete object with static storage duration or to a function.</td>
<tr><td>Pointer to member</td>
    <td>Arbitrary constant expression</td>
<tr><td><tt>std::nullptr_t</tt></td>
    <td>Arbitrary constant expression</td></tr>
</table>

<p>The restriction that the constant expression must name a complete object
is retained to avoid aliasing problems with pointers to subobjects:

<pre class="extract">
struct A { int x, y; } a;
template&lt;int*> struct Z;
using B = Z&lt;&a.x + 1>;
using C = Z&lt;&a.y>;
// Are B and C the same type?
</pre>

<p>Additionally, the (previously implicit) restriction against string literals,
temporaries, and <tt>typeid</tt> expressions is retained, because those
expressions are not required to produce the same object each time they are
evaluated.

<p>This paper also proposes to allow the conversions permitted in converted
constant expressions for all non-type template arguments. In particular, this
allows lvalue-to-rvalue conversions (supporting <tt>constexpr</tt> globals of
the type of the template parameter) and user-defined conversions (supporting
arguments of literal class type with appropriate user-defined <tt>constexpr</tt>
conversion operators). Such conversions are already permitted for non-type
template parameters of integral or enumeration type.

<h2><a name="Wording">Proposed Wording</a></h2>

<p>
Change in 5.19 (expr.const) paragraph 3:
<blockquote class="std">
  [...]
A <i>converted constant expression</i> of type <tt>T</tt> is an expression, implicitly
converted to <del>a prvalue of</del> type <tt>T</tt>,
where the converted expression is a <del>core</del>
constant expression and the implicit conversion sequence contains only
user-defined conversions, lvalue-to-rvalue conversions (4.1),
<ins>
array-to-pointer conversions (4.2),
function-to-pointer conversions (4.3),
qualification conversions (4.4),
</ins>
integral promotions (4.5), <del>and</del> integral conversions (4.7) other than narrowing conversions (8.5.4)<ins>,</ins>
<ins>and null pointer conversions (4.10) and null member pointer conversions (4.11) from <tt>std::nullptr_t</tt>,
and where the reference binding (if any) binds directly</ins>.
[ <em>Note:</em> such expressions may be used in <tt>new</tt> expressions
(5.3.4), as <tt>case</tt> expressions (6.4.2), as enumerator initializers if
the underlying type is fixed (7.2), as array bounds (8.3.4), and as <del>integral or
  enumeration</del> non-type template arguments (14.3). — end note ]
</blockquote>

<em>Drafting note: previously, a converted constant expression could only be of integral or enumeration type, so these conversions do not change any existing uses of the term.</em>

<p>
Change in 14.3.2 (temp.arg.nontype) paragraph 1 and remove the bullets:

<blockquote class="std">
A <i>template-argument</i> for a non-type<del>, non-template</del> <i>template-parameter</i> shall be <del>one of:</del>
<ul>
<li><del>for a non-type <i>template-parameter</i> of integral or enumeration type,</del>
a converted constant expression (5.19) of the type of the
<i>template-parameter</i><ins>.</ins><del>; or</del>
<li><del>the name of a non-type <i>template-parameter</i>; or</del>
<li><del>a constant expression (5.19) that designates the address of a complete object
<del>with static storage duration and external or internal linkage or a
function with external or internal linkage, including function
templates and function <i>template-ids</i> but excluding non-static class members, expressed
(ignoring parentheses) as <tt>&</tt> <i>id-expression</i>, where the <i>id-expression</i>
is the name of an object or function, except that the <tt>&</tt> may be omitted if the
name refers to a function or array and shall be omitted if the corresponding
<i>template-parameter</i> is a reference; or</del>
<li><del>a constant expression that evaluates to a null pointer value (4.10); or</del>
<li><del>a constant expression that evaluates to a null member pointer value (4.11); or</del>
<li><del>a pointer to member expressed as described in 5.3.1; or</del>
<li><del>a constant expression of type <tt>std::nullptr_t</tt></del>.
</ul>
<ins>For a non-type <i>template-parameter</i> of reference type or pointer type, the
  value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):
  <ul><li>a subobject (1.8),
      <li>a temporary object (12.2),
      <li>a string literal (2.14.5),
      <li>the result of a <tt>typeid</tt> expression (5.2.8), or
      <li>a predefined <tt>__func__</tt> variable (8.4.1).
  </ul>
  [ <em>Note:</em> If the <i>template-argument</i> represents a set of overloaded functions (or a pointer or member pointer to such), the matching function is selected from the set (13.4). ]</ins>
</blockquote>

<p>Change in 14.3.2 (temp.arg.nontype) paragraph 2:

<blockquote class="std">
[ <i>Note:</i> <del>A string literal (2.14.5) does not satisfy the requirements
  of any of these categories and thus is not an acceptable
  <i>template-argument</i>.</del>
<ins>String literals are not acceptable <i>template-argument</i>s.</ins>
[ <i>Example:</i> ... ] ]
</blockquote>

<p>Change in 14.3.2 (temp.arg.nontype) paragraph 3:

<blockquote class="std">
[ <em>Note:</em>
Addresses of array elements and names or addresses of non-static class members are not acceptable
<i>template-arguments</i>.
[ <em>Example:</em>
<pre class="example">
template&lt;int* p> class X { };

int a[10];
struct S { int m; static int s; } s;

X&lt;&a[2]> x3; // error: address of array element
X&lt;&s.m> x4;  // error: address of non-static member
X&lt;&s.s> x5;  // <del>error: &S::s must be used</del> <ins>OK: address of static member</ins>
X&lt;&S::s> x6; // OK: address of static member
</pre>
] ]
</blockquote>

<p>Change in 14.3.2 (temp.arg.nontype) paragraph 4:

<blockquote class="std">
[ <em>Note:</em> Temporaries<del>, unnamed lvalues, and named lvalues with no linkage</del> are not acceptable
<i>template-argument</i>s when the corresponding <i>template-parameter</i> has reference type. [ <em>Example:</em> ... ] ]
</blockquote>

<p>Delete all of 14.3.2 (temp.arg.nontype) paragraph 5 other than its example and move it to before paragraph 2:

<blockquote class="std">
  <del>The following conversions are performed on each expression used as a non-type <em>template-argument</em>. If a non-type <em>template-argument</em> cannot be converted to the type of the corresponding <em>template-parameter</em> then the program is ill-formed.
<ul><li>...</ul>
</del>
[ <em>Example:</em> ... ]
</blockquote>

<p>Change in 14.4 (temp.type) paragraph 1:

<blockquote class="std">
Two <i>template-id</i>s refer to the same class, function, or variable if
<ul>
<li>their <i>template-name</i>s, <i>operator-function-id</i>s, or <i>literal-operator-id</i>s refer to the same template and
<li>their corresponding type <i>template-argument</i>s are the same type and
<li>their corresponding non-type template arguments of integral or enumeration type have identical values and
<li>their corresponding non-type template-arguments of pointer type refer to the same <del>external</del> object or
    function or are both the null pointer value and
<li>their corresponding non-type template-arguments of pointer-to-member type refer to the same class
    member or are both the null member pointer value and
<li>their corresponding non-type template-arguments of reference type refer to the same <del>external</del> object
    or function and
<li>their corresponding template template-arguments refer to the same template.
</ul>
[ <em>Example:</em> ... ]
</blockquote>
