<html>
<head>
<title>P0292R0: 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>
P0292R0<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Audience: Core Working Group<br/>
2016-03-17<br/>

<h1>P0292R0: 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>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 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. A <code>case</code> or <code>default</code> label appearing
within such an if statement shall be associated with
a <code>switch</code> statement (6.4.2 [stmt.switch]) within the same
if statement. A label (6.1 [stmt.label]) declared in a discarded
statement shall not be referred to by a statement (6.6.4 [stmt.goto])
outside of a discarded statement.  When a <code>constexpr</code> if
statement appears in a templated entity, during an instantiation of
the enclosing template or generic lambda, a discarded statement is not
instantiated.

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

[ Note: Odr-uses (3.2 [basic.def.odr]) in a discarded
statement do not require an entity to be defined. -- end note ]

</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 in the body of
the function, if any <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> if
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> if 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> if
statement (6.4.1 [stmt.if])</ins> that does not require instantiation.

</blockquote>




</body>
</html>
