<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2101: Some transformation types can produce impossible types</title>
<meta property="og:title" content="Issue 2101: Some transformation types can produce impossible types">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2101.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#C++17">C++17</a> status.</em></p>
<h3 id="2101"><a href="lwg-defects.html#2101">2101</a>. Some transformation types can produce impossible types</h3>
<p><b>Section:</b> 21.3.9 <a href="https://wg21.link/meta.trans">[meta.trans]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2011-11-18 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>3
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>

<p>
Table 53 &mdash; "Reference modifications" says in regard to the type trait 
<code>add_lvalue_reference</code> (emphasize mine)
</p>

<blockquote>
<p>
If <code>T</code> names an object or <strong>function</strong> type then the member typedef type
shall name <code>T&amp;</code>;
</p>
</blockquote>

<p>
The problem with this specification is that function types with <i>cv</i>-qualifier or <i>ref</i>-qualifier, 
like
</p>
<blockquote><pre>
void() const
void() &amp;
</pre></blockquote>
<p>
are also affected by the first part of the rule, but this would essentially mean, that
instantiating <code>add_lvalue_reference</code> with such a type would attempt to form
a type that is not defined in the C++ type system, namely
</p>
<blockquote><pre>
void(&amp;)() const
void(&amp;)() &amp;
</pre></blockquote>
<p>
The general policy for <i>TransformationTrait</i>s is to define always some meaningful 
mapping type, but this does not hold for <code>add_lvalue_reference</code>, <code>add_rvalue_reference</code>,
and in addition to these two for <code>add_pointer</code> as well. The latter one would 
attempt to form the invalid types
</p>
<blockquote><pre>
void(*)() const
void(*)() &amp;
</pre></blockquote>
<p>
A possible reason why those traits were specified in this way is that in C++03 (and that means
for TR1), <i>cv</i>-qualifier were underspecified in the core language and several compilers
just ignored them during template instantiations. This situation became fixed by adopting
CWG issues <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#295">295</a> and 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#547">547</a>.
<p/>
While there is possibly some core language clarification needed (see reflector messages
starting from c++std-core-20740), it seems also clear that the library should fix the
specification. The suggested resolution follows the style of the specification of the
support concepts <code>PointeeType</code> and <code>ReferentType</code> defined in 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf">N2914</a>.
</p>


<p><i>[2012-02-10, Kona]</i></p>

<p>
Move to NAD.
</p>
<p>
These cv- and ref-qualified function types are aberrations in the type system, and do
not represent any actual entity defined by the language.  The notion of cv- and ref-
qualification applies only to the implicit <code>*this</code> reference in a member function.
</p>
<p>
However, these types can be produced by quirks of template metaprogramming, the question
remains what the library should do about it.  For example, <code>add_reference</code> returns
the original type if passed a reference type, or a <code>void</code> type.  Conversely,
<code>add_pointer</code> will return a pointer to the referenced type when passed a reference.
</p>
<p>
It is most likely that the 'right' answer in any case will depend on the context that the
question is being asked, in terms of forming these obscure types.  The best the LWG can
do is allow an error to propagate back to the user, so they can provide their own meaningful
answer in their context - with additional metaprogramming on their part.  The consensus is
that if anyone is dangerous enough with templates to get themselves into this problem, they
will also have the skills to resolve the problem themselves.  This is not going to trip up
the non-expert developer.
</p>
<p>
Lastly, it was noted that this problem arises only because the language is inconsistent in
providing us these nonsense types that do no really represent anything in the language.
There may be some way Core or Evolution could give us a more consistent type system so that
the LWG does not need to invent an answer at all, should this question need resolving.  This
is another reason to not specify anything at the LWG trait level at this time, leaving the
other working groups free to produce the 'right' answer that we can then follow without
changing the meaning of existing, well-defined programs.
</p>

<p><i>[2012-02-10, post-Kona]</i></p>

<p>
Move back to Open. Daniel is concerned that this is not an issue we can simply ignore,
further details to follow.
</p>

<p><i>[2012-10-06, Daniel comments]</i></p>

<p>
This issue really should be resolved as a defect: First, the argument that "forming these obscure types"
should "allow an error to propagate" is inconsistent with the exact same "obscure type" that would be formed
when <code>std::add_lvalue_reference&lt;void&gt;</code> wouldn't have an extra rules for <code>void</code> types, which
also cannot form references. The originally proposed resolution attempts to apply the same solution for the same 
common property of <code>void</code> types and function types with <em>cv</em>-qualifiers or <em>ref</em>-qualifier.
These functions had the property of <code>ReferentType</code> during concept time (see 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#749">CWG 749</a> bullet three for the final 
wording).
<p/>
Core issue <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1417">CWG 1417</a> has clarified
that any attempt to form a reference of a pointer to a function type with <em>cv</em>-qualifiers or 
<em>ref</em>-qualifier is ill-formed. Unfortunately, many compilers don't implement this yet.
<p/>
I also would like to warn about so-called "obscure" types: The problem is that these can occur as the side effect
of finding a best match overload of function templates, where this type is exactly correct for one of these
overloads, but causes a deep (not-sfinae-friendly) error for others where one of these traits are part of the 
signature.
<p/>
Existing experience with <code>void</code> types shows, that this extra rule is not so unexpected. Further, any usage 
of the result types of these traits as argument types or return types of functions would make these ill-formed 
(and in a template context would be sfinaed away), so the expected effects are rarely unnoticed. Checking
all existing explicit usages of the traits <code>add_rvalue_reference</code>, <code>add_lvalue_reference</code>, and
<code>add_pointer</code> didn't show any example where the error would be silent: <code>add_rvalue_reference</code>
is used to specify the return value of <code>declval()</code> and the instantiation of <code>declval&lt;void() const&gt;()</code>
would be invalid, because of the attempt to return a function type. Similarly, <code>add_lvalue_reference</code>
is used to specify the return type of <code>unique_ptr&lt;T&gt;::operator*()</code>. Again, any instantiation with 
<code>void() const</code> wouldn't remain unnoticed. The trait <code>add_pointer</code> is used to specify the trait
<code>std::decay</code> and this is an interesting example, because it is well-formed when instantiated with <code>void</code> 
types, too, and is heavily used throughout the library specification. All use-cases would not be negatively affected 
by the suggested acceptance of function types with <em>cv</em>-qualifiers or <em>ref</em>-qualifier, because they involve 
types that are either function arguments, function parameters or types were references are formed from.
<p/>
The alternative would be to add an additional extra rule that doesn't define a type member 'type' when
we have a function type with <em>cv</em>-qualifiers or <em>ref</em>-qualifier. This is better than the
current state but it is not superior than the proposal to specify the result as the original type, because
both variants are sfinae-friendly. A further disadvantage of the "non-type" approach here would be that any
usage of <code>std::decay</code> would require special protection against these function types, because 
instantiating <code>std::decay&lt;void() const&gt;</code> again would lead to a deep, sfinae-unfriendly error.
<p/>
The following example demonstrates the problem: Even though the second <code>f</code> template is the best final
match here, the first one will be instantiated. During that process <code>std::decay&lt;T&gt;::type</code>
becomes instantiated as well and will raise a deep error, because as part of the implementation the trait
<code>std::add_pointer&lt;void() const&gt;</code> becomes instantiated:
</p>
<blockquote><pre>
#include &lt;type_traits&gt;

template&lt;class T&gt;
typename std::decay&lt;T&gt;::type f(T&amp;&amp; t);

template&lt;class T, class U&gt;
U f(U u);

int main() {
  f&lt;void() const&gt;(0);
}
</pre></blockquote>
<p>
When the here proposed resolution would be applied this program would be well-formed and selects the expected function.
</p>

<p>
<strong>Previous resolution from Daniel [SUPERSEDED]:</strong>
</p>
<blockquote class="note">
<ol>
<li><p>Change Table 53 &mdash; "Reference modifications" in 21.3.9.3 <a href="https://wg21.link/meta.trans.ref">[meta.trans.ref]</a> as indicated:</p>

<table border="1">
<caption>Table 53 &mdash; Reference modifications</caption>
<tr>
<th>Template</th>
<th>Comments</th>
</tr> 

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct<br/>
add_lvalue_reference;</code>
</td>
<td>
If <code>T</code> names an object <code>type</code> or <ins>if <code>T</code> names a</ins> function type <ins>that does not have<br/>
<i>cv</i>-qualifiers or a <i>ref</i>-qualifier</ins> then the member typedef <code>type</code><br/>
shall name <code>T&amp;</code>; otherwise, if <code>T</code> names a type "rvalue reference to <code>T1</code>" then<br/>
the member typedef <code>type</code> shall name <code>T1&amp;</code>; otherwise, <code>type</code> shall name <code>T</code>.
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct<br/>
add_rvalue_reference;</code>
</td>
<td>
If <code>T</code> names an object <code>type</code> or <ins>if <code>T</code> names a</ins> function type <ins>that does not have<br/>
<i>cv</i>-qualifiers or a <i>ref</i>-qualifier</ins> then the member typedef <code>type</code><br/>
shall name <code>T&amp;&amp;</code>; otherwise, <code>type</code> shall name <code>T</code>. [<i>Note</i>: This rule reflects<br/>
the semantics of reference collapsing (9.3.4.3 <a href="https://wg21.link/dcl.ref">[dcl.ref]</a>). For example, when a type <code>T</code><br/>
names a type <code>T1&amp;</code>, the type <code>add_rvalue_reference&lt;T&gt;::type</code> is not an<br/>
rvalue reference. &mdash; <i>end note</i>]
</td>
</tr>
</table>

</li>

<li><p>Change Table 56 &mdash; "Pointer modifications" in 21.3.9.6 <a href="https://wg21.link/meta.trans.ptr">[meta.trans.ptr]</a> as indicated:</p>

<table border="1">
<caption>Table 56 &mdash; Pointer modifications</caption>
<tr>
<th>Template</th>
<th>Comments</th>
</tr> 

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct add_pointer;</code>
</td>
<td>
<del>The member typedef <code>type</code> shall name the same type as</del><br/>
<ins>If <code>T</code> names a function type that has <i>cv</i>-qualifiers or a <i>ref</i>-qualifier<br/>
then the member typedef <code>type</code> shall name <code>T</code>; otherwise, it<br/> 
shall name the same type as</ins> <code>remove_reference&lt;T&gt;::type*</code>.
</td>
</tr>

</table>

</li>
</ol>
</blockquote>

<p>
The following revised proposed resolution defines - in the absence of a proper core language definition - a new
term <em>referenceable type</em> as also suggested by the resolution for LWG <a href="lwg-defects.html#2196" title="Specification of is_*[copy/move]_[constructible/assignable] unclear for non-referencable types (Status: C++14)">2196</a><sup><a href="https://cplusplus.github.io/LWG/issue2196" title="Latest snapshot">(i)</a></sup> as an
umbrella of the negation of <code>void</code> types and function types with <em>cv</em>-qualifiers or <em>ref</em>-qualifier. 
This simplifies and minimizes the requires wording changes.
</p>

<p><i>[
2013-09-26, Daniel synchronizes wording with recent draft
]</i></p>


<p><i>[
2014-05-18, Daniel synchronizes wording with recent draft and comments
]</i></p>


<p>
My impression is that this urgency of action this issue attempts to point out is partly caused by the fact that even for
the most recent C++14 compilers the implementations have just recently changed to adopt the core wording. Examples for these
are bug reports to <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61182">gcc</a> or 
<a href="http://llvm.org/bugs/show_bug.cgi?id=19742">clang</a>.
<p/>
Occasionally the argument has been presented to me that the suggested changes to the traits affected by this issue would
lead to irregularities compared to other traits, especially the lack of guarantee that <code>add_pointer</code> might not return
a pointer or that <code>add_(l/r)value_reference</code> might not return a reference type. I would like to point out that this
kind of divergence is actually already present in most <code>add/remove</code> traits: For example, we have no guarantee that
<code>add_const</code> returns a const type (Reference types or function types get special treatments), or that <code>add_rvalue_reference</code>
returns an rvalue-reference (e.g. when applied to an lvalue-reference type).
<p/>
Zhihao Yuan brought to my attention, that the originally proposing paper 
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2002/n1345.html">N1345</a> carefully discussed these design choices.
</p>

<p><i>[2015-05, Lenexa]</i></p>

<p>
MC: move to Ready: in favor: 16, opposed: 0, abstain: 1<br/>
STL: have libstdc++, libc++ implemented this? we would need to change your implementation<br/>
</p>


<p id="res-2101"><b>Proposed resolution:</b></p>
<p>This wording is relative to N3936.</p>

<ol>
<li><p>Change Table 53 &mdash; "Reference modifications" in 21.3.9.3 <a href="https://wg21.link/meta.trans.ref">[meta.trans.ref]</a> as indicated:</p>

<table border="1">
<caption>Table 53 &mdash; Reference modifications</caption>
<tr>
<th>Template</th>
<th>Comments</th>
</tr> 

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct<br/>
add_lvalue_reference;</code>
</td>
<td>
If <code>T</code> names <del>an object or function type</del><ins>a referenceable type</ins><br/>
then the member typedef <code>type</code><br/>
shall name <code>T&amp;</code>; otherwise, <del>if <code>T</code> names a type "rvalue reference to <code>T1</code>" then<br/>
the member typedef <code>type</code> shall name <code>T1&amp;</code>; otherwise,</del> <code>type</code> shall name <code>T</code>.<br/>
<ins>[<i>Note</i>: This rule reflects the semantics of reference collapsing (9.3.4.3 <a href="https://wg21.link/dcl.ref">[dcl.ref]</a>). &mdash; <i>end note</i>]</ins>
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct<br/>
add_rvalue_reference;</code>
</td>
<td>
If <code>T</code> names <del>an object or function type</del><ins>a referenceable type</ins><br/>
then the member typedef <code>type</code><br/>
shall name <code>T&amp;&amp;</code>; otherwise, <code>type</code> shall name <code>T</code>. [<i>Note</i>: This rule reflects<br/>
the semantics of reference collapsing (9.3.4.3 <a href="https://wg21.link/dcl.ref">[dcl.ref]</a>). For example, when a type <code>T</code><br/>
names a type <code>T1&amp;</code>, the type <code>add_rvalue_reference_t&lt;T&gt;</code> is not an<br/>
rvalue reference. &mdash; <i>end note</i>]
</td>
</tr>
</table>

</li>

<li><p>Change Table 56 &mdash; "Pointer modifications" in 21.3.9.6 <a href="https://wg21.link/meta.trans.ptr">[meta.trans.ptr]</a> as indicated:</p>

<table border="1">
<caption>Table 56 &mdash; Pointer modifications</caption>
<tr>
<th>Template</th>
<th>Comments</th>
</tr> 

<tr>
<td colspan="2" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code>template &lt;class T&gt;<br/>
struct add_pointer;</code>
</td>
<td>
<ins>If <code>T</code> names a referenceable type or a (possibly <i>cv</i>-qualified) <code>void</code> type then<br/></ins>
<del>T</del><ins>t</ins>he member typedef <code>type</code> shall name the same type as<br/>
<code>remove_reference_t&lt;T&gt;*</code><ins>; otherwise, <code>type</code> shall name <code>T</code></ins>.
</td>
</tr>

</table>

</li>
</ol>





</body>
</html>
