<html>
<head>
<title>P0292R2: constexpr if: A slightly different syntax</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 }
  .rule { background-color:#FFFF40 }
  .ex { background-color: #D0FFF0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }  
  strong { font-weight: inherit; color: #2020ff }
</style>
</head>

<body>
P0292R2<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Audience: Core Working Group<br/>
2016-06-20<br/>

<h1>P0292R2: constexpr if: A slightly different syntax</h1>

<h2>Introduction</h2>

The paper P0128R1 "constexpr if" by Ville Voutilainen proposes a very
useful facility to write compact template code that is instantiated
depending on a compile-time condition.  The motivation and rationale
is sound and not repeated here.
<p>
This paper proposes a slightly different syntax, namely

<pre>
  if constexpr(cond)
     statement1;
  else
     statement2;
</pre>

The differences vs. P0128R1 are:

<ul>

<li><code>constexpr</code> is placed before the condition, indicating that the
condition is evaluated as a compile-time constant.</li>

<li><code>constexpr</code> is not repeated before or after the
<code>else</code>; an <code>else</code> binds to the nearest preceding
if-statement as before (regardless of <code>constexpr</code>)</li>

<li>a constexpr if is valid in a non-template and suppresses
requirements for entity definitions in the non-taken branch</li>

<li><code>return</code> statements in a non-taken branch are ignored
for return type deduction</li>

</ul>

This syntax avoids seemingly disingenous repetitions of constexpr in if ... else if ... chains:

<pre>
  // P0128R1
  constexpr if (cond)
    statement1;
  constexpr else constexpr if (cond)
    statement2;
  constexpr else constexpr if (cond)
    statement3;
  constexpr else
    statement4;
</pre>

Compare with the syntax proposed in this paper:
<pre>
  if constexpr (cond)
    statement1;
  else if constexpr (cond)
    statement2;
  else if constexpr (cond)
    statement3;
  else
    statement4; 
</pre>

<p>
The proposed syntax was approved by EWG during the Jacksonville
(2016-03) meeting of WG21.
<p>

The wording below incorporates initial feedback from CWG.


<h2>Not proposed</h2>

Disarming <code>static_assert</code> declarations in the non-taken
branch of a constexpr if is not proposed.

<pre>
void f() {
  if constexpr (false)
    static_assert(false);   // ill-formed
}

template&lt;class T>
void g() {
  if constexpr (false)
    static_assert(false);   // ill-formed; no diagnostic required for template definition
}
</pre>

<h2>Changes compared to P0292R1 (see <strong>blue</strong> text)</h2>

<ul>
  <li>disallow referring to labels across constexpr if boundaries</li>
  <li>minor wording fixes due to CWG review</li>
  <li>incorporate CWG and EWG feedback: instantiating the condition
  vs. determining that a substatement is discarded for nested
  templates and generic lambdas</li>
</ul>

<h2>Changes compared to P0292R0 (see <strong>blue</strong> text)</h2>

<ul>
<li>slight wording improvements</li>
</ul>


<h2>Wording</h2>

The wording is based on the wording presented in P0128R1 with
modifications for the changes explained above.
<p>

Change in 3.2 [basic.def.odr] paragraph 4:

<blockquote>
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program <ins>outside of
a discarded statement (6.4.1
[stmt.if])</ins>; no diagnostic required. The definition can
appear explicitly in the program, it can be found in the standard or a
user-defined library, or (when appropriate) it is implicitly defined
(see 12.1, 12.4 and 12.8). An inline function shall be defined in
every translation unit in which it is odr-used <ins>outside of
a discarded statement</ins>.
    
</blockquote>
  
Change in 6.4 [stmt.select] paragraph 1:

<blockquote>
<pre>
<em>selection-statement</em>:
       if <ins>constexpr<sub>opt</sub></ins> ( <em>condition</em> ) <em>statement</em>
       if <ins>constexpr<sub>opt</sub></ins> ( <em>condition</em> ) <em>statement</em> else <em>statement</em>
       switch ( <em>condition</em> ) <em>statement</em>
</pre>

See 8.3 [dcl.meaning] for the optional <em>attribute-specifier-seq</em> in a
condition.  In Clause 6, the term substatement refers to the
contained statement or statements that appear in the syntax
notation. ...

</blockquote>

Add a new paragraph after 6.4.1 [stmt.if] paragraph 1:

<blockquote class="new">
If the parenthesized <em>condition</em> is prefixed with
<code>constexpr</code>, the <strong>value of the</strong> condition
shall be a contextually converted constant expression of
type <code>bool</code> (5.20 [expr.const]); this form is called
a <em>constexpr if</em> statement.  If the value of the converted
condition is false, the first substatement is a <em>discarded
statement</em>, otherwise the second substatement, if present, is a
discarded statement.

<strong>During the instantation of an enclosing templated entity, if
the condition is not value-dependent after its instantiation, the
discarded substatement (if any) is not instantiated.</strong>

<!-- When a <code>constexpr</code> if statement appears in a templated
entity, a discarded statement is not instantiated <strong>during the
instantiation of the innermost enclosing templated
entity</strong>. -->

[ Note: Odr-uses (3.2 [basic.def.odr]) in a discarded statement do not
require an entity to be defined. -- end note ] A <code>case</code>
or <code>default</code> label appearing within such an <code>if</code> statement
shall be associated with a <code>switch</code> statement (6.4.2
[stmt.switch]) within the same <code>if</code> statement. <strong>A label (6.1
[stmt.label]) declared in a substatement of a constexpr <code>if</code> statement
shall only be referred to by a statement (6.6.4 [stmt.goto]) in the
same substatement.</strong>  [ Example:

<pre>
    template&lt;typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) {
      // ... handle p
      if constexpr (sizeof...(rs) > 0)
        g(rs...);  // never instantiated with an empty argument list.
    }

    extern int x;   // no definition of x required
    int f() {
      if constexpr (true)
        return 0;
      else if (x)
        return x;
      else
        return -x;
    }
</pre>
--- end example]

</blockquote>


Change in 7.1.6.4 [dcl.spec.auto] paragraph 2:

<blockquote>
... If the declared return type of the function contains a placeholder
type, the return type of the function is deduced
from <ins>non-discarded</ins> <code>return</code> statements<ins><strong>, if any,</strong></ins> in the body of
the function<del>, if any</del> <ins>(6.4.1 [stmt.if])</ins>.

</blockquote>

Change in 7.1.6.4 [dcl.spec.auto] paragraph 7:

<blockquote>
When a variable declared using a placeholder type is initialized,
or a <ins>non-discarded</ins> return statement occurs in a
function declared with a return type that contains a placeholder type,
the deduced return type or variable type is determined from the type
of its initializer. ...

</blockquote>


Change in 7.1.6.4 [dcl.spec.auto] paragraphs 9-11:

<blockquote>
If a function with a declared return type that contains a placeholder
type has multiple <ins>non-discarded</ins> return statements, the return
type is deduced for each return statement. If the type deduced is not
the same in each deduction, the program is ill-formed.
<p>
If a function with a declared return type that uses a placeholder type
has no <ins>non-discarded</ins> return statements, the return type is
deduced as though from a return statement with no operand at the
closing brace of the function body. [ Example: ... ]
<p>
Once a <ins>non-discarded</ins> return statement has been
seen in a function, however, the return type deduced from that
statement can be used in the rest of the function, including in other
return statements. ...

</blockquote>

Change in 14.5 [temp.decls] paragraph 2 as follows:

<blockquote>
For purposes of name lookup and instantiation, default arguments and
<em>exception-specification</em>s of function templates and default
arguments and <em>exception-specification</em>s of member functions of
class templates are considered definitions; each default argument or
<em>exception-specification</em> is a separate definition which is
unrelated to the function template definition or to any other default
arguments or <em>exception-specification</em>s. <ins>For the purpose
of instantiation, the substatements of
a <code>constexpr</code> <code>if</code> statement (6.4.1 [stmt.if])
are considered definitions.</ins>

</blockquote>


Change in 14.6 [temp.dep] paragraph 8:

<blockquote>
... If no valid specialization can be generated for a template <ins>or
a substatement of a <code>constexpr</code> <code>if</code> statement
(6.4.1 [stmt.if]) within a template</ins>,
and <del>that</del> <ins>the</ins> template is not instantiated, the
template is ill-formed, no diagnostic required. ...

</blockquote>

Change 14.7.1 [temp.inst] paragraph 11 as follows:

<blockquote>
An implementation shall not implicitly instantiate a function
template, a variable template, a member template, a non-virtual member
function, a member class, <del>or</del> a static data member of a
class template, <ins>or a substatement of
a <code>constexpr</code> <code>if</code> statement (6.4.1
[stmt.if])</ins> <del>that does not require
instantiation</del> <ins><strong>, unless such instantiation is
required</strong></ins>.

</blockquote>


<h2>Acknowledgements</h2>

Thanks to Walter Brown for suggestions for wording improvement.



</body>
</html>
