<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2049: is_destructible is underspecified</title>
<meta property="og:title" content="Issue 2049: is_destructible is underspecified">
<meta property="og:description" content="C++ library issue. Status: C++14">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2049.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++14">C++14</a> status.</em></p>
<h3 id="2049"><a href="lwg-defects.html#2049">2049</a>. <code>is_destructible</code> is underspecified</h3>
<p><b>Section:</b> 21.3.6.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a> <b>Status:</b> <a href="lwg-active.html#C++14">C++14</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2011-04-18 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#meta.unary.prop">active issues</a> in [meta.unary.prop].</p>
<p><b>View all other</b> <a href="lwg-index.html#meta.unary.prop">issues</a> in [meta.unary.prop].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++14">C++14</a> status.</p>
<p><b>Discussion:</b></p>
<p>The conditions for the type trait <code>is_destructible</code> to be true
are described in Table 49 &mdash; Type property predicates:</p>
<blockquote><p>
For a complete type <code>T</code> and given<br/>
<code>template &lt;class U&gt;
struct test { U u; };</code>,<br/>
<code>test&lt;T&gt;::~test()</code> is not deleted.
</p></blockquote>

<p>This specification does not say what the result would be for function
types or for abstract types:</p>
<ol>
<li>For an abstract type <code>X</code> the instantiation <code>test&lt;X&gt;</code>
is already ill-formed, so we cannot say anything about whether the destructor
would be deleted or not.</li>
<li>In regard to function types, there exists a special rule in the core language, 13.4.2 <a href="https://wg21.link/temp.arg.type">[temp.arg.type]</a> p. 3,
which excludes member functions to be declared via the type of the template parameter:
<blockquote><p>
If a declaration acquires a function type through a type dependent on a <i>template-parameter</i>
and this causes a declaration that does not use the syntactic form of a function declarator 
to have function type, the program is ill-formed. 
<p/>
[ <i>Example</i>:</p>
<blockquote><pre>
template&lt;class T&gt; struct A {
  static T t;
};
typedef int function();
A&lt;function&gt; a; // ill-formed: would declare A&lt;function&gt;::t
               // as a static member function
</pre></blockquote>
<p>
&mdash; <i>end example</i> ]
</p></blockquote>
which has the same consequence as for abstract types, namely that the corresponding
instantiation of <code>test</code> is already ill-formed and we cannot say anything
about the destructor.
</li>
</ol>
<p>To solve this problem, I suggest to specify function types as trivially and nothrowing
destructible, because above mentioned rule is very special for templates. For non-templates,
a typedef can be used to introduce a member as member function as clarified in 9.3.4.6 <a href="https://wg21.link/dcl.fct">[dcl.fct]</a>
p. 10.</p>
<p>For abstract types, two different suggestions have been brought to my attention:
Either declare them as unconditionally non-destructible or check whether the expression
</p>
<blockquote><pre>
std::declval&lt;T&amp;&gt;().~T()
</pre></blockquote>
<p>is well-formed in an unevaluated context. The first solution is very easy to specify,
but the second version has the advantage for providing more information to user-code. This 
information could be quite useful, if generic code is supposed to invoke the destructor
of a reference to a base class indirectly via a delete expression, as suggested by
Howard Hinnant:</p>
<blockquote><pre>
template &lt;class T&gt;
my_pointer&lt;T&gt;::~my_pointer() noexcept(is_nothrow_destructible&lt;T&gt;::value)
{
   delete ptr_;
}
</pre></blockquote>
<p>Additional to the <code>is_destructible</code> traits, its derived forms <code>is_trivially_destructible</code>
and <code>is_nothrow_destructible</code> are similarly affected, because their wording refers to "the indicated
destructor" and probably need to be adapted as well.</p>

<p><i>[
2011 Bloomington
]</i></p>


<p>
After discussion about to to handle the exceptional cases of reference types, function types (available by defererencing a function pointer)
and <code>void</code> types, Howard supplied proposed wording.
</p>

<p><i>[
2011-08-20 Daniel comments and provides alternatives wording
]</i></p>


<p>
The currently proposed wording would have the consequence that 
<em>every</em> array type is not destructible, because the pseudo-destructor
requires a scalar type with the effect that the expression
</p><blockquote><pre>
std::declval&lt;T&amp;&gt;().~T()
</pre></blockquote><p>
is not well-formed for e.g. <code>T</code> equal to <code>int[3]</code>. The intuitive
solution to fix this problem would be to adapt the object type case to refer to 
the expression
</p><blockquote><pre>
std::declval&lt;U&amp;&gt;().~U()
</pre></blockquote><p>
with <code>U</code> equal to <code>remove_all_extents&lt;T&gt;::type</code>, but that
would have the effect that arrays of unknown bounds would be destructible, if 
the element type is destructible, which was not the case before (This was 
intentionally covered by the special "For a complete type T" rule in
the FDIS).
<p/>
Suggestion: Use the following definition instead:
</p>
<blockquote><p>
Let <code>U</code> be <code>remove_all_extents&lt;T&gt;::type</code>.<br/>
For incomplete types and function types, <code>is_destructible&lt;T&gt;::value</code> is <code>false</code>.<br/>
For object types, if the expression <code>std::declval&lt;U&amp;&gt;().~U()</code> is well-formed<br/>
when treated as an unevaluated operand (Clause 5), then <code>is_destructible&lt;T&gt;::value</code><br/>
is <code>true</code>, otherwise it is <code>false</code>.<br/>
For reference types, <code>is_destructible&lt;T&gt;::value</code> is <code>true</code>.
</p></blockquote>
<p>
This wording also harmonizes with the "unevaluated operand" phrase
used in other places, there does not exist the definition of an
"unevaluated context"
<p/>
<em>Note:</em> In the actually proposed wording this wording has been slightly reordered with the same effects. 
</p>

<p><strong>Howard's (old) proposed resolution:</strong></p>
<blockquote class="note">
<p>
Update 21.3.6.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a>, table 49:
</p>

<table border="1">
<tr>
<td><code>template &lt;class T&gt;
struct is_destructible;</code></td>
<td>
<del>For a complete type <code>T</code> and given <code>template &lt;class U&gt; struct test { U u; };</code>, <code>test&lt;T&gt;::~test()</code> is not deleted.
</del>
<br/>
<ins>
For object types, if the expression: <code>std::declval&lt;T&amp;>().~T()</code> is well-formed in an unevaluated context then
<code>is_destructible&lt;T>::value</code> is <code>true</code>, otherwise it is <code>false</code>.
<br/>
For <code>void</code> types, <code>is_destructible&lt;T>::value</code> is <code>false</code>.
<br/>
For reference types, <code>is_destructible&lt;T>::value</code> is <code>true</code>.
<br/>
For function types, <code>is_destructible&lt;T>::value</code> is <code>false</code>.
</ins>
</td>
<td><code>T</code> shall be a complete type, (possibly cv-qualified) <code>void</code>, or an array of unknown bound.</td>
</tr>
</table>
</blockquote>
<p>
</p>

<p><i>[2012, Kona]</i></p>

<p>
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
</p>

<p><i>[2012, Portland: applied to WP]</i></p>




<p id="res-2049"><b>Proposed resolution:</b></p>

<p>
Update 21.3.6.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a>, table 49:
</p>

<table border="1">
<tr>
<td><code>template &lt;class T&gt;
struct is_destructible;</code></td>
<td>
<del>For a complete type <code>T</code> and given <code>template &lt;class U&gt; struct test { U u; };</code>, <code>test&lt;T&gt;::~test()</code> is not deleted.
</del>
<br/>
<ins>
For reference types, <code>is_destructible&lt;T&gt;::value</code> is <code>true</code>.<br/>
For incomplete types and function types, <code>is_destructible&lt;T&gt;::value</code> is <code>false</code>.<br/>
For object types and given <code>U</code> equal to <code>remove_all_extents&lt;T&gt;::type</code>,<br/> 
if the expression <code>std::declval&lt;U&amp;&gt;().~U()</code> is well-formed when treated as an<br/>
unevaluated operand (Clause 7 <a href="https://wg21.link/expr">[expr]</a>), then <code>is_destructible&lt;T&gt;::value</code> is <code>true</code>,<br/>
otherwise it is <code>false</code>.<br/>
</ins>
</td>
<td><code>T</code> shall be a complete type, (possibly cv-qualified) <code>void</code>, or an array of unknown bound.</td>
</tr>
</table>






</body>
</html>
