<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- ===================================================================== -->
<!--  File:       TypeInfoAsIndex.html                                     -->
<!--  Author:     J. Kanze                                                 -->
<!--  Date:       03/02/2008                                               -->
<!--      Copyright (c) 2008 James Kanze                                   -->
<!-- _____________________________________________________________________ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
  <meta http-equiv="content-language" content="en"/>
  <meta name="author" content="J. Kanze"/>
  <meta name="date" content="2008-02-03T15:01:37CET"/>
  <meta name="generator" content="vim"/>
  <title>Making It Easier to Use std::type_info as an Index in an Associative Container</title>
  <style type="text/css">
    <!--
    .added { color:darkcyan; text-decoration:underline; }
    .removed { color:red; text-decoration:line-through; }
    .constraint { padding-left:2em; }
    .clause { padding-left:5em; }
    .hlabel { padding-right:1em; text-align:right; }
    -->
  </style>
</head>
<body>
  <h1>Making It Easier to Use <tt>std::type_info</tt> as an Index in an Associative Container</h1>
<p>
<table rules="none" style="margin-left:60%">
  <tr><td class="hlabel">Doc. no.:</td><td>N2530=08-0040</td></tr>
  <tr><td class="hlabel">Date:</td><td>2008-02-03</td></tr>
  <tr><td class="hlabel">Author:</td><td>James Kanze</td></tr>
  <tr><td class="hlabel">email:</td><td><a href="mailto:james.kanze@gmail.com">james.kanze@gmail.com</a></td></tr>
</table>
</p>
<hr>
<h2>Motivation and scope</h2>
<p>
  One of the most frequent uses of <tt>std::type_info</tt> is as an
  index in a associative container, for example, mapping a type
  identifier to a factory function.  Currently, this is more difficult
  than necessary for the associative containers defined in
  [associative], and impossible to do reliably for the unordered
  containers defined in [unord].  This proposal consists of two parts:
  the first to add support for unordered containers to
  <tt>std::type_info</tt> itself, and the second to provide a simple
  wrapper class which can be used directly as an index type in any of
  the associative containers (ordered or unordered).
</p>
<h2>Adding support for unordered containers to <tt>std::type_info</tt></h2>
<h3>Proposed text</h3>
<p>
  In [type.info], in the class definition:
</p>
<blockquote>
  <pre>
    namespace std {
      class type_info {
      public:
        virtual ~type_info();
        bool operator==(const type_info&amp; rhs) const;
        bool operator!=(const type_info&amp; rhs) const;
        bool before(const type_info&amp; rhs) const;
        <span class="added">size_t hash_code() const throw();</span>
        const char* name() const;
        type_info(const type_info&amp; rhs) = delete; // cannot be copied
        type_info&amp; operator=(const type_info&amp; rhs) = delete; // cannot be copied
      };
    }
  </pre>
</blockquote>
<p>
  In [type.info], after paragraph 6, add the following paragraphs:
</p>
<blockquote>
  <p><tt>size_t hash_code() const throw</tt></p>
  <p class=constraint><i>Returns:</i> an unspecified value, except that
  within a single execution of the program, two <tt>type_info</tt> which
  compare equal should return equal values.
  <p class=constraint><i>Remarks:</i> as far as possible, an
  implementation should attempt to return different values when the
  <tt>type_info</tt> it is called on do not compare equal.</p>
</blockquote>
<h3>Rationale</h3>
<p>
  It was not felt necessary (nor particularly easy to implement) to
  require that the hash value be the same across different program runs.
  This means that it cannot be used for external hashing, e.g. in a
  file.  This is not really a constraint, however, since the
  <tt>type_info</tt> cannot be write to or read from an external source
  either.  If some sort of mapping or type identity is needed in an
  external source, the user must define his own identity type, and can
  define a hash code for it if needed.
</p>
<p>
  The added function, <tt>hash_code</tt> must be nothrow if it is to be
  used in a specialization of <tt>hash</tt>, since [unord.hash] says
  that the <tt>operator()</tt> shall not throw exceptions.  (For that
  matter, is there any reason to allow <tt>operator==</tt>,
  <tt>operator!=</tt> and <tt>below</tt> to throw?)
</p>
<h3>Implementation considerations</h3>
<p>
  A trivial implementation would simply calculate a hash code over the
  return value of name().  Implementations should be encouraged to do
  better: for example, if the implementation guarantees that there is
  only one instance of the <tt>type_info</tt> for each type (typical for
  Unix implementations, I think), then it could simply convert the
  address into a size_t (using <tt>reinterpret_cast</tt>).
</p>
<h2>Class <tt>type_index</tt></h2>
<h3>Proposed text</h3>
<p>
  After [type.info], add a section [type.index], as follows:
</p>
<blockquote>
  <h4>18.6.2 Class <tt>type_index</tt></h4>
  <p>
  <pre>
    namespace std {
      class type_index {
      public:
        type_index( const type_info&amp; rhs );
        bool operator==( const type_index&amp; rhs ) const;
        bool operator!=( const type_index&amp; rhs ) const;
        bool operator&lt; (const type_index&amp; rhs ) const;
        bool operator&lt;= (const type_index&amp; rhs ) const;
        bool operator&gt; (const type_index&amp; rhs ) const;
        bool operator&gt;= (const type_index&amp; rhs ) const;
        size_t hash_code() const;
        const char* name() const;
      private:
        <i>// const type_info* target;    //  exposition only.
        // Note that the use of a pointer here, rather than a reference,
        // means that the default copy constructor and assignment
        // operator will be provided and work as expected.</i>
      };

      template&lt;&gt;
      struct hash&lt; type_index &gt; : public std::unary_function< type_index, size_t > {
        size_t operator()( type_index index ) const;
      }
    }
  </pre>
  </p>
  <p>
    The class <tt>type_index</tt> provides a simple wrapper for
    <tt>type_info</tt> which can be used as an index type in associative
    containers [associative] and in unordered associative containers
    [unord].
  </p>
  <h5>18.6.2.1 <tt>type_index</tt> member functions</h5>
  <p>
    <tt>type_index::type_index( const type_info&amp; rhs )</tt>
  </p>
  <p class="constraint">
    <i>Effects:</i> constructs a <tt>type_index</tt>, the equivalent of:
    <tt>target = &amp;rhs ;</tt>
  </p>
  <p>
    <tt>bool operator==(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>*target == *rhs.target</tt>
  </p>
  <p>
    <tt>bool operator!=(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>*target != *rhs.target</tt>
  </p>
  <p>
    <tt>bool operator&lt;(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>target-&gt;before( *rhs.target )</tt>
  </p>
  <p>
    <tt>bool operator&lt;=(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>! rhs.target-&gt;before( *target )</tt>
  </p>
  <p>
    <tt>bool operator&gt;(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>rhs.target-&gt;before( *target )</tt>
  </p>
  <p>
    <tt>bool operator&gt;=(const type_index&amp; rhs) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>! target-&gt;before( *rhs.target )</tt>
  </p>
  <p>
    <tt>size_t hash_code() const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>target-&gt;hash_code()</tt>
  </p>
  <p>
    <tt>const char* name() const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>target-&gt;name()</tt>
  </p>
  <h5>18.6.2.2 template specialization <tt>hash&lt;type_index&gt;</tt></h5>
  <p>
    <tt>size_t operator()( type_index index ) const;</tt>
  </p>
  <p class="constraint">
    <i>Returns:</i> <tt>index.hash_code()</tt>
  </p>
</blockquote>
<h3>Rationale</h3>
<p>
  Obviously, a user could easily implement something like this himself.
  Still, it seems to cover a common use case, in which it seems
  preferable that users not be required to reinvent the wheel each time.
  I have something very similar in my own library&mdash;the main difference
  is that it uses the naming conventions of my library, and not those of
  the standard&mdash;and I'm certain that many others do as well.
</p>
<p>
  Strictly speaking, I don't see any need or use for <tt>name()</tt>,
  but given that the class presents itself as a fassade, there doesn't
  seem any justifiable reason to not provide it either.  (For that
  matter, I don't see any real need for any of the relation operators
  except &lt;, but the rule of least surprise suggests that if one is
  present, they all are.)
</p>
</body>
</html>
<!-- Local Variables:               === for emacs -->
<!-- mode: html                     === for emacs -->
<!-- tab-width: 8                   === for emacs -->
<!-- End:                           === for emacs -->
<!-- vim: set ts=8 filetype=html:   === for vim   -->

