<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2543: LWG 2148 (hash support for enum types) seems under-specified</title>
<meta property="og:title" content="Issue 2543: LWG 2148 (hash support for enum types) seems under-specified">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2543.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#Resolved">Resolved</a> status.</em></p>
<h3 id="2543"><a href="lwg-defects.html#2543">2543</a>. LWG 2148 (hash support for enum types) seems under-specified</h3>
<p><b>Section:</b> 22.10.19 <a href="https://wg21.link/unord.hash">[unord.hash]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Ville Voutilainen <b>Opened:</b> 2015-09-27 <b>Last modified:</b> 2017-02-02</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#unord.hash">issues</a> in [unord.hash].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The rationale in issue <a href="lwg-defects.html#2148" title="Hashing enums should be supported directly by std::hash (Status: C++14)">2148</a><sup><a href="https://cplusplus.github.io/LWG/issue2148" title="Latest snapshot">(i)</a></sup> says:
</p>
<blockquote class="note"><p>
This proposed resolution doesn't specify anything else about the
primary template, allowing implementations to do whatever they want
for non-enums: <code>static_assert</code> nicely, explode horribly at compiletime
or runtime, etc.
</p></blockquote>
<p>
libc++ seems to implement it by defining the primary template and
<code>static_assert</code>ing <code>is_enum</code> inside it. However, that brings forth
a problem; there are reasonable SFINAE uses broken by it:
</p>
<blockquote><pre>
#include &lt;type_traits&gt;
#include &lt;functional&gt;

class S{}; // No hash specialization

template&lt;class T&gt;
auto f(int) -&gt; decltype(std::hash&lt;T&gt;(), std::true_type());

template&lt;class T&gt;
auto f(...) -&gt; decltype(std::false_type());

static_assert(!decltype(f&lt;S&gt;(0))::value, "");
</pre></blockquote>
<p>
MSVC doesn't seem to accept that code either.
<p/>
There <em>is</em> a way to implement LWG <a href="lwg-defects.html#2148" title="Hashing enums should be supported directly by std::hash (Status: C++14)">2148</a><sup><a href="https://cplusplus.github.io/LWG/issue2148" title="Latest snapshot">(i)</a></sup> so that <code>hash</code> for enums is supported
without breaking that sort of SFINAE uses:
</p>
<ol>
<li><p>Derive the main <code>hash</code> template from a library-internal uglified-named
base template that takes a type and a <code>bool</code>, pass as argument for the base
the result of <code>is_enum</code>.</p></li>
<li><p>Partially specialize that base template so that the false-case has
a suitable set of private special member function declarations so that it's not
an aggregate nor usable in almost any expression.</p></li>
</ol>

<p><i>[2015-10, Kona Saturday afternoon]</i></p>

<p>EricWF to come back with wording; move to Open</p>

<p><i>[2016-05-08, Eric Fiselier &amp; Ville provide wording]</i></p>


<p><i>[2016-05-25, Tim Song comments]</i></p>

<p>
I see two issues with this P/R:
</p>
<ol>
<li><p>
"for which neither the library nor the user provides an explicit specialization" should probably be "for which neither 
the library nor the user provides an explicit or partial specialization".
</p></li>
<li><p>
Saying that the specialization "is not <code>DefaultConstructible</code> nor <code>MoveAssignable</code>" is not enough to 
guarantee that common SFINAE uses will work. Both of those requirements have several parts, and it's not too hard 
to fail only some of them. For instance, not meeting the assignment postcondition breaks <code>MoveAssignable</code>, 
but is usually not SFINAE-detectible. And for <code>DefaultConstructible</code>, it's easy to write something in a way 
that breaks <code>T()</code> but not <code>T{}</code> (due to aggregate initialization in the latter case).
</p></li>
</ol>

<p><i>[2016-06-14, Daniel comments]</i></p>

<p>
The problematic part of the P/R is that it describes constraints that would be suitable if they were constraints 
for user-code, but they are not suitable as requirements imposed on implementations to provide certain guarantees 
for clients of the Library. The guarantees should be written in terms of testable compile-time expressions, e.g. based on 
negative results of <code>is_default_constructible&lt;hash&lt;X&gt;&gt;::value</code>, 
<code>std::is_copy_constructible&lt;hash&lt;X&gt;&gt;::value</code>, and possibly also 
<code>std::is_destructible&lt;hash&lt;X&gt;&gt;::value</code>. <em>How</em> an implementation realizes these negative 
results shouldn't be specified, though, but the expressions need to be well-formed and well-defined.

<p><i>[2016-08-03, Ville provides revised wording as response to Daniel's previous comment]</i></p>

</p>

<strong>Previous resolution [SUPERSEDED]:</strong>
<blockquote class="note">
<p>
This wording is relative to N4582.
</p>

<ol>
<li><p>Insert a new paragraph after 22.10.19 <a href="https://wg21.link/unord.hash">[unord.hash]</a>/2</p>

<blockquote>
<p>
-2- The template specializations shall meet the requirements of class template <code>hash</code> (20.12.14).
<p/>
<ins>-?- For any type that is not of integral or enumeration type, or for
which neither the library nor the user provides an explicit
specialization of the class template <code>hash</code>, the specialization of <code>hash</code> does not meet
any of the <code>Hash</code> requirements, and is not <code>DefaultConstructible</code> nor
<code>MoveAssignable</code>.
[<i>Note</i>: this means that the specialization of <code>hash</code> exists, but any
attempts to use it as a Hash will be ill-formed. &mdash; <i>end note</i>]
</ins>
</p>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2016-08 - Chicago]</i></p>

<p>Thurs AM: Moved to Tentatively Ready</p>

<strong>Previous resolution [SUPERSEDED]:</strong>
<blockquote class="note">
<p>
This wording is relative to N4606.
</p>

<ol>
<li><p>Insert a new paragraph after 22.10.19 <a href="https://wg21.link/unord.hash">[unord.hash]</a>/2</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> I see no reason to specify whether <code>H&lt;T&gt;</code> is
destructible. There's no practical use case for which that would need to be covered. 
libstdc++ makes it so that <code>H&lt;T&gt;</code> is destructible.]
</p>
</blockquote>

<blockquote>
<p>
-2- The template specializations shall meet the requirements of class template <code>hash</code> (20.12.14).
<p/>
<ins>-?- For any type <code>T</code> that is not of integral or enumeration type, or for
which neither the library nor the user provides an explicit or partial specialization of the class
template hash, the specialization of <code>hash&lt;T&gt;</code> has the following properties:
</ins>
</p>
<ul>
<li><ins><code>is_default_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_copy_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_move_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_copy_assignable_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_move_assignable_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_callable_v&lt;hash&lt;T&gt;, T&amp;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_callable_v&lt;hash&lt;T&gt;, const T&amp;&gt;</code> is <code>false</code></ins></li>
</ul>
<p>
<ins>[<i>Note:</i> this means that the specialization of <code>hash</code> exists, but any
attempts to use it as a <code>Hash</code> will be ill-formed. &mdash; end note]</ins>
</p>
</blockquote>
</li>
</ol></blockquote>

<p><i>[2016-08-09 Daniel reopens]</i></p>

<p>
As pointed out by Eric, the usage of <code>is_callable</code> is incorrect.
Eric provides new wording.
</p>

<p><i>[2016-09-09 Issues Resolution Telecon]</i></p>

<p>Move to Tentatively Ready</p>

<p><i>[2016-11-12, Issaquah]</i></p>

<p>Resolved by P0513R0</p>


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

<ol>
<li><p>Insert a new paragraph after 22.10.19 <a href="https://wg21.link/unord.hash">[unord.hash]</a>/2</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> I see no reason to specify whether <code>H&lt;T&gt;</code> is
destructible. There's no practical use case for which that would need to be covered. 
libstdc++ makes it so that <code>H&lt;T&gt;</code> is destructible.]
</p>
</blockquote>

<blockquote>
<p>
-2- The template specializations shall meet the requirements of class template <code>hash</code> (20.12.14).
<p/>
<ins>-?- For any type <code>T</code> that is not of integral or enumeration type, or for
which neither the library nor the user provides an explicit or partial specialization of the class
template hash, the specialization of <code>hash&lt;T&gt;</code> has the following properties:
</ins>
</p>
<ul>
<li><ins><code>is_default_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_copy_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_move_constructible_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_copy_assignable_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>is_move_assignable_v&lt;hash&lt;T&gt;&gt;</code> is <code>false</code></ins></li>
<li><ins><code>hash&lt;T&gt;</code> is not a function object type (22.10 <a href="https://wg21.link/function.objects">[function.objects]</a>)</ins></li>
</ul>
<p>
<ins>[<i>Note:</i> this means that the specialization of <code>hash</code> exists, but any
attempts to use it as a <code>Hash</code> will be ill-formed. &mdash; end note]</ins>
</p>
</blockquote>
</li>
</ol>





</body>
</html>
