<!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.5em; padding-right: 0.5em; }

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

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; }

p.grammarlhs { margin-bottom: 0 }
p.grammarrhs { margin-left:8em; margin-top:0; text-indent:-4em }

</style>

<title>constexpr member functions and implicit const</title>
</head>

<body>

<div style="text-align: right; float: right">
<p>ISO/IEC JTC1 SC22 WG21<br>N3598<br>Richard Smith<br>2013-03-12</p>
</div>

<h1><tt>constexpr</tt> member functions and implicit <tt>const</tt></h1>

<h2>Problem</h2>

<p>In C++11, <tt>constexpr</tt> member functions are implicitly <tt>const</tt>.
This creates problems for literal class types which desire to be usable both
within constant expressions and outside them:</p>

<pre class="extract"><code>struct A {
  constexpr A() : n(3) {}
  constexpr int getN() const /*implicit*/ { return n; }
  int n;
};
struct B {
  constexpr B() : a() {}
  constexpr const A &amp;getA() const /*implicit*/ { return a; }
  A &amp;getA() { return a; }            // cannot make this 'constexpr'
  A a;
};
constexpr int n = B().getA().getN(); // error, selected overload for
                                     // B::getA() is not constexpr.
</code></pre>

<p>This problem only exists for the implicit <tt>this</tt> parameter to a
function; <tt>constexpr</tt> functions can have parameters of (non-const)
<tt>T *</tt> and <tt>T &amp;</tt>.</p>

<h2>Analysis</h2>

<p>Several alternatives have been suggested to resolve this problem:</p>

<ul>
  <li>Accept the status quo, and require users to work around this minor
  embarrassment with <tt>const_cast</tt>.</li>

  <li>Remove the rule that <tt>constexpr</tt> member functions are implicitly
  <tt>const</tt>.<br/>
  <b>Pro:</b> user code is clean, and experience suggests that many users are
  writing the <tt>const</tt> explicitly anyway.<br/>
  <b>Con:</b> not backwards compatible, and <tt>const</tt> is often the right
  behavior for a <tt>constexpr</tt> member function.</li>

  <li>Add a new qualifier to remove the <tt>const</tt> implicitly added to a
  <tt>constexpr</tt> member function.<br/>
  <b>Pro:</b> backwards compatible.<br/>
  <b>Con:</b> has been described as "hard to teach" and "subject to ridicule".
  </li>
</li>
</ul>

<p>If we select the second option, the backwards-compatibility issue can be
made less severe by encouraging implementors to diagnose <tt>constexpr</tt>
but not explicitly <tt>const</tt> member functions in their C++11 modes.</p>

<h2>Proposed wording</h2>

<h3>Option 2</h3>

<p>Change in [dcl.constexpr] (7.1.5)/6:</p>

<blockquote class="std">
  If the instantiated template specialization of a constexpr function template
  or member function of a class template would fail to satisfy the requirements
  for a constexpr function or constexpr constructor, that specialization is not
  a constexpr function or constexpr constructor. <del>[ Note: If the function is
  a member function it will still be const as described below. — end note
  ]</del> If no specialization of the template would yield a constexpr
  function or constexpr constructor, the program is ill-formed; no diagnostic
  required.
</blockquote>

<p>Change in [dcl.constexpr] (7.1.5)/8:</p>

<blockquote class="std">
  <del>A <tt>constexpr</tt> specifier for a non-static member function that is
  not a constructor declares that member function to be <tt>const</tt>
  (9.3.1). [ Note:</del> The <tt>constexpr</tt> specifier has no
  <del>other</del> effect on the <del>function</del> type <ins> of a constexpr
  function or a constexpr constructor</ins>. <del>— end note ] The keyword
  <tt>const</tt> is ignored if it appears in the <i>cv-qualifier-seq</i> of
  the function declarator of the declaration of such a member function.</del>
  The class of which <del>that</del> <ins>a constexpr</ins> function is a member
  shall be a literal type (3.9). [ <i>Example:</i>
  <pre>
  class debug_flag {
  public:
    explicit debug_flag(bool);
    constexpr bool is_on() <ins>const</ins>; // error: debug_flag not
                                  // literal type
  private:
    bool flag;
  };
  constexpr int bar(int x, int y) // OK
      { return x + y + x*y; }
  // ...
  int bar(int x, int y)           // error: redefinition of bar
      { return x * 2 + 3 * y; }
  </pre>
  — <i>end example</i> ]
</blockquote>

<h3>Option 3</h3>

<p>Strawman syntax: allow <tt>mutable</tt> in the location where <tt>const</tt>
would be written: <code class="extract">constexpr A &amp;getA() mutable { return
  a; }</code></p>

<p>Change the grammar for <i>parameters-and-qualifiers</i> in [dcl.decl] (8)/4:</p>

<blockquote class="std">
  <p class="grammarlhs"><i>parameters-and-qualifiers:</i></p>
  <p class="grammarrhs">
  <code>(</code> <i>parameter-declaration-clause</i> <code>)</code>
  <ins><tt>mutable</tt><i><sub>opt</sub></i></ins>
  <i>
    cv-qualifier-seq<sub>opt</sub>
    ref-qualifier<sub>opt</sub>
    exception-specification<sub>opt</sub>
    attribute-specifier-seq<sub>opt</sub>
  </i></p>
</blockquote>

<p>Change in [dcl.fct] (8.3.5)/1:</p>

<blockquote class="std">
  In a declaration <code>T D</code> where <code>D</code> has the form
  <p class="grammarrhs">
  <code>D1 (</code> <i>parameter-declaration-clause</i> <code>)</code>
  <ins><tt>mutable</tt><i><sub>opt</sub></i></ins>
  <i>
    cv-qualifier-seq<sub>opt</sub>
    ref-qualifier<sub>opt</sub>
    exception-specification<sub>opt</sub>
    attribute-specifier-seq<sub>opt</sub>
  </i>
  [...]
</blockquote>

<p>Change in [dcl.fct] (8.3.5)/2:</p>

<blockquote class="std">
  In a declaration <code>T D</code> where <code>D</code> has the form
  <p class="grammarrhs">
  <code>D1 (</code> <i>parameter-declaration-clause</i> <code>)</code>
  <ins><tt>mutable</tt><i><sub>opt</sub></i></ins>
  <i>
    cv-qualifier-seq<sub>opt</sub>
    ref-qualifier<sub>opt</sub>
    exception-specification<sub>opt</sub>
    attribute-specifier-seq<sub>opt</sub>
    trailing-return-type
  </i>
  [...]
</blockquote>

<p>Add a new paragraph after [dcl.fct] (8.3.5)/6:</p>

<blockquote class="stdins">
  If <code>mutable</code> is part of a function declarator,
  <code>const</code> shall not be present in the <i>cv-qualifier-seq</i> and
  that declarator shall be used to declare a non-static member function.
  [ Note: Such a function is not <code>const</code> even if it is declared with
  the <code>constexpr</code> specifier. — end note ]
</blockquote>

<p>Change in [dcl.constexpr] (7.1.5)/8:</p>

<blockquote class="std">
  A <tt>constexpr</tt> specifier for a non-static member function that is
  not a constructor <ins>and is not declared with the <code>mutable</code>
  keyword</ins> declares that member function to be <tt>const</tt>
  (9.3.1). [ Note: The <tt>constexpr</tt> specifier has no
  other effect on the function type. — end note ] The keyword
  <tt>const</tt> is ignored if it appears in the <i>cv-qualifier-seq</i> of
  the function declarator of the declaration of such a member function.
  The class of which that function is a member shall be a literal type (3.9). [
  <i>Example:</i> [...] — <i>end example</i> ]
</blockquote>

</li>
</ul>

</body>
</html>
