title: Hashing by either one of two members
body: <p>While this question is with regard to c++, it is a general hashing question which might answer for other languages as well.</p>
  
  <p>I have a class that is identified by <strong>either</strong> one of 2 members it holds (let's call them device &amp; name).</p>
  
  <pre><code>class Foo {
      static const int NO_DEVICE = 0;
  
      bool isDeviceSet() {
          return device != NO_DEVICE;
      }
  
  private:
      int device;
      std::string name;
  };
  </code></pre>
  
  <p>I would like to identify a <code>Foo</code> instance with priority to the <code>device</code> (when it's set).<br>
  Meaning, when <code>device</code> is set I would like to hash according to <code>device</code> (<strong>alone!</strong> - so that two <code>Foo</code>s with the same <code>device</code> and different <code>name</code>s will be considered the same object hash wise).<br>
  And when the <code>device</code> is not set I would like to hash according to <code>name</code>.</p>
  
  <p><strong>My question:</strong></p>
  
  <blockquote>
    <p>Is hashing by either one of the members safe enough?</p>
  </blockquote>
  
  <p>For example, hashing by either one would look like this:</p>
  
  <pre><code>namespace std {
      size_t hash&lt;Foo&gt;::operator()(Foo const&amp; f) const {
          if (f.isDeviceSet()) {
              return std::hash&lt;int&gt;()(f.deviceId);
          }
          return std::hash&lt;std::string&gt;()(f.name);
       }
  }
  </code></pre>
  
  <p>The problem with this is that one could argue that (according to each hash function's implementation), the probability for 2 different <code>Foo</code>s, one with a <code>device</code> set and one without a <code>device</code> set, to have the same hash code is unknown (however highly unlikely).</p>
  
  <ul>
  <li>Consider an int hash function that converts to a string and calls string's hash - this will result in <code>Foo{2, "bar"}</code> and <code>Foo{0, "2"}</code> having the same hash code.</li>
  </ul>
  
  <p>On the other hand, I'm not sure whether combining <code>isDeviceSet()</code> in the hash would really give better results (for the general case - obviously it solves the example in the bullet above):</p>
  
  <pre><code>namespace std {
      size_t hash&lt;Foo&gt;::operator()(Foo const&amp; f) const {
          if (f.isDeviceSet()) {
              std::pair&lt;bool, int&gt; p(f.isDeviceSet(), f.device);
              boost::hash&lt; std::pair&lt;bool, int&gt; &gt; hasher;
              return hasher(p);
          }
          std::pair&lt;bool, std::string&gt; p(f.isDeviceIdSet(), f.name);
          boost::hash&lt; std::pair&lt;bool, std::string&gt; &gt; hasher;
          return hasher(p);
       }
  }
  </code></pre>
  
  <p>Any insights / other hash ideas are welcome.</p>