<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3205: decay_t in the new common_type fallback should be remove_cvref_t</title>
<meta property="og:title" content="Issue 3205: decay_t in the new common_type fallback should be remove_cvref_t">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3205.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="3205"><a href="lwg-active.html#3205">3205</a>. <code>decay_t</code> in the new <code>common_type</code> fallback should be <code>remove_cvref_t</code></h3>
<p><b>Section:</b> 21.3.9.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Casey Carter <b>Opened:</b> 2019-05-12 <b>Last modified:</b> 2022-04-25</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#meta.trans.other">issues</a> in [meta.trans.other].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
<a href="https://wg21.link/p0898r4">P0898R4</a> "The One Ranges Proposal" added a new fallback case to 
the definition of <code>common_type</code> in 21.3.9.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a>, bullet 3.3.4:
</p>
<blockquote style="border-left: 3px solid #ccc;padding-left: 15px;">
<p>
Otherwise, if <code><i>COND_RES</i>(<i>CREF</i>(D1), <i>CREF</i>(D2))</code> denotes a type, let <code>C</code> 
denote the type <code>decay_t&lt;<i>COND_RES</i>(<i>CREF</i>(D1), <i>CREF</i>(D2))&gt;</code>.
</p>
</blockquote>
<p>
Per para 3.3, <code>D1</code> and <code>D2</code> are decayed types. If both are <code>void</code>, bullet 3.3.4 
is not reached. If either is an abominable function type or <code>void</code>, the <code><i>COND_RES</i></code> 
type expression above is ill-formed and bullet 3.3.4 does not apply. In all cases in which the 
<code><i>COND_RES</i></code> expression is well-formed, <code>D1</code> and <code>D2</code> denote <i>cv</i>-unqualified 
non-array object types. Given that fact, (1) <code><i>CREF</i>(D1)</code> and <code><i>CREF</i>(D2)</code> 
are equivalent to <code>const D1&amp;</code> and <code>const D2&amp;</code>, respectively, and (2) the 
<code><i>COND_RES</i></code> expression is equivalent to <code>decltype(false ? 
declval&lt;const D1&amp;&gt;() : declval&lt;const D1&amp;&gt;())</code>, i.e., the second and third 
operands of the conditional operator are lvalues of type <code>const D1</code> and <code>const D2</code>, respectively.
<p/>
[expr.cond]/3 cannot apply since the operands are not glvalue bit-fields.
<p/>
If <code>D1</code> and <code>D2</code> are the same type, [expr.cond]/4 does not apply. If <code>D1</code> and 
<code>D2</code> are different types, there are a few cases to consider:
</p>
<ol>
<li><p>If [expr.cond]/4.1 applies, one operand is converted into an lvalue reference to the type of the other, 
i.e., both resulting operands are lvalues of type either <code>const D1</code> or <code>const D2</code>.</p></li>
<li><p>[expr.cond]/4.2 cannot apply since neither operand is an xvalue.</p></li>
<li><p>[expr.cond]/4.3.1 cannot apply since it would imply that the operands have the same type.</p></li>
<li><p>If [expr.cond]/4.3.2 applies &mdash; if either <code>D1</code> or <code>D2</code> is a base class of the 
other &mdash; again the resulting operands are lvalues of type either <code>const D1</code> or <code>const D2</code>.</p></li>
<li><p>If [expr.cond]/4.3.3 applies, the either the <code>const D1&amp;</code> operand converts to 
<code>const D2</code> or the <code>const D2&amp;</code> operand converts to <code>const D1</code>.</p></li>
<li><p>If none of the sub-bullets in [expr.cond]/4 applies, the operands are left unchanged.</p></li>
</ol>
<p>
[expr.cond]/5 applies if the operands initially had the same type, or in cases 1 and 4 above. The 
conditional expression is an lvalue of type <code>const D1</code> or <code>const D2</code>, and the 
<code><i>COND_RES</i></code> expression yields <code>const D1&amp;</code> or <code>const D2&amp;</code>.
<p/>
Only cases 5 and 6 reach [expr.cond]/6. This paragraph performs overload resolution, which may result 
in converting both operands to the same non-class type to invoke a builtin conditional operator "overload". 
<p/>
[expr.cond]/7 applies standard conversions including array-to-pointer and function-to-pointer conversion to the operands. Consequently, the operands are once more "decayed" if [expr.cond]/6 converted them to an array or function type. Again case-by-case:
</p>
<ol>
<li><p>[expr.cond]/7.1 applies if the operands now have the same type, which is the type of the conditional 
expression.</p></li>
<li><p>[expr.cond]/7.2 applies if the operands have arithmetic or enumeration type; the conditional expression yields the result of applying the usual arithmetic conversions.</p></li>
<li><p>[expr.cond]/7.3 applies if the operands have pointer type; the conditional expression yields their composite pointer type.</p></li>
<li><p>[expr.cond]/7.4 applies if the operands have pointer-to-member type; the conditional expression applies some more standard conversions and yields their composite pointer type.</p></li>
<li><p>[expr.cond]/7.5 applies if one operand has type <code>nullptr_t</code> and the other is either a null 
pointer constant or has type <code>nullptr_t</code>; the conditional expression yields <code>nullptr_t</code>.</p></li>
</ol>
<p>
In every case above, the conditional expression is either ill-formed, an lvalue of type <code>const D1</code> or 
<code>const D2</code>, or a prvalue of a non-array non-function type. Consequently the <code><i>COND_RES</i></code> 
type expression always yields a non-array non-function type, for which <code>decay_t</code> and <code>remove_cvref_t</code> 
are equivalent. We can therefore replace <code><i>COND_RES</i>(<i>CREF</i>(D1), <i>CREF</i>(D2))</code> in
[meta.trans.other]/3.3.4 with <code>decltype(false ? declval&lt;const D1&amp;&gt;() : 
declval&lt;const D2&amp;&gt;())</code>, and replace the usage of <code>decay_t</code> with <code>remove_cvref_t</code>.
<p/>
Furthermore, there are now quite a few different cases describing the behavior of <code>common_type</code>. 
It's not clear that <code>common_type&lt;T...&gt;::type</code> is always a decayed type without in-depth analysis. 
We should non-normatively clarify that fact.
</p>

<p><i>[2019-06-12 Priority set to 3 after reflector discussion]</i></p>


<p><i>[2020-05-01; Daniel adjusts wording to recent working draft]</i></p>


<p><i>[2022-04-25; Daniel adjusts wording to recent working draft]</i></p>



<p id="res-3205"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/N4910" title=" Working Draft, Standard for Programming Language C++">N4910</a>.
</p>

<ol>
<li><p>Modify 21.3.9.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a> as indicated:</p>

<blockquote>
<p>
-2- Let:
</p>
<ol style="list-style-type: none">
<li><p><del>(2.1) &mdash; <code><i>CREF</i>(A)</code> be 
<code>add_lvalue_reference_t&lt;const remove_reference_t&lt;A&gt;&gt;</code>,</del></p></li>
<li><p>(2.2) &mdash; [&hellip;]</p></li>
<li><p>[&hellip;]</p></li>
<li><p>(2.9) &mdash; [&hellip;]</p></li>
</ol>
<p>
If any of the types computed above is ill-formed, then <code><i>COMMON-REF</i>(A, B)</code> is ill-formed.
<p/>
-3- Note A: For the <code>common_type</code> trait applied to a template parameter pack <code>T</code> of types, the member 
<code>type</code> shall be either defined or not present as follows:
</p>
<ol style="list-style-type: none">
<li><p>(3.1) &mdash; [&hellip;]</p></li>
<li><p>(3.2) &mdash; [&hellip;]</p></li>
<li><p>(3.3) &mdash; If <code>sizeof...(T)</code> is two, let the first and second types constituting <code>T</code> 
be denoted by <code>T1</code> and <code>T2</code>, respectively, and let <code>D1</code> and <code>D2</code> denote the 
same types as <code>decay_t&lt;T1&gt;</code> and <code>decay_t&lt;T2&gt;</code>, respectively.</p>
<ol style="list-style-type: none">
<li><p>(3.3.1) &mdash; [&hellip;]</p></li>
<li><p>(3.3.2) &mdash; [&hellip;]</p></li>
<li><p>(3.3.3) &mdash; Otherwise, if</p>
<blockquote><pre>
decay_t&lt;decltype(false ? declval&lt;D1&gt;() : declval&lt;D2&gt;())&gt;
</pre></blockquote>
<p>
denotes a valid type, let <code>C</code> denote that type.
</p>
</li>
<li><p>(3.3.4) &mdash; Otherwise, if <del><code><i>COND-RES</i>(<i>CREF</i>(D1), <i>CREF</i>(D2))</code></del></p>
<blockquote><pre>
<ins>remove_cvref_t&lt;decltype(false ? declval&lt;const D1&amp;&gt;() : declval&lt;const D2&amp;&gt;())&gt;</ins>
</pre></blockquote>
<p> 
denotes a type, let <code>C</code> denote th<del>e</del><ins>at</ins> type 
<del><code>decay_t&lt;<i>COND-RES</i>(<i>CREF</i>(D1), <i>CREF</i>(D2))&gt;</code></del>.</p></li>
</ol>
</li>
<li><p>(3.4) &mdash; [&hellip;]</p></li>
</ol>
<p>
<ins>[<i>Note:</i> Whenever the <i>qualified-id</i> <code>common_type&lt;T...&gt;::type</code> is valid, 
it denotes the same type as <code>decay_t&lt;common_type&lt;T...&gt;::type&gt;</code>. &mdash; <i>end note</i>]</ins>
<p/>
-4- Note B: [&hellip;]
</p>
</blockquote>
</li>

</ol>




</body>
</html>
