title: C++ templates: conditionally enabled member function
body: <p>I'm creating a very small C++ project, and I'd like to create a simple vector class for my own needs. The <code>std::vector</code> template class will not do. When the vector class is comprised of <code>char</code>s (i.e. <code>vector&lt;char&gt;</code>), I'd like it to be able to be compared to a <code>std::string</code>. After a bit of messing around, I wrote code that both compiles and does what I want. See below:</p>
  
  <pre><code>#include &lt;string&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  template &lt;typename ElementType&gt;
  class WorkingSimpleVector {
   public:
      const ElementType * elements_;
      size_t count_;
  
      // ...
  
      template &lt;typename ET = ElementType&gt;
      inline typename std::enable_if&lt;std::is_same&lt;ET, char&gt;::value &amp;&amp; std::is_same&lt;ElementType, char&gt;::value, bool&gt;::type
      operator==(const std::string &amp; other) const {
          if (count_ == other.length())
          {
              return memcmp(elements_, other.c_str(), other.length()) == 0;
          }
          return false;
      }
  };
  
  template &lt;typename ElementType&gt;
  class NotWorkingSimpleVector {
   public:
      const ElementType * elements_;
      size_t count_;
  
      // ...
  
      inline typename std::enable_if&lt;std::is_same&lt;ElementType, char&gt;::value, bool&gt;::type
      operator==(const std::string &amp; other) const {
          if (count_ == other.length())
          {
              return memcmp(elements_, other.c_str(), other.length()) == 0;
          }
          return false;
      }
  };
  
  int main(int argc, char ** argv) {
      // All of the following declarations are legal.
      WorkingSimpleVector&lt;char&gt; wsv;
      NotWorkingSimpleVector&lt;char&gt; nwsv;
      WorkingSimpleVector&lt;int&gt; wsv2;
      std::string s("abc");
  
      // But this one fails: error: no type named ‘type’ in ‘struct std::enable_if&lt;false, bool&gt;’
      NotWorkingSimpleVector&lt;int&gt; nwsv2;
  
      (wsv == s);  // LEGAL (wanted behaviour)
      (nwsv == s);  // LEGAL (wanted behaviour)
      // (wsv2 == s);  // ILLEGAL (wanted behaviour)
      // (nwsv2 == s);  // ??? (unwanted behaviour)
  }
  </code></pre>
  
  <p>I believe I understand why the error is occurring: The compiler creates the class definition for <code>NotWorkingSimpleVector&lt;int&gt;</code>, and then the return type of my <code>operator==</code> function becomes:</p>
  
  <pre><code>std::enable_if&lt;std::is_same&lt;int, char&gt;::value, bool&gt;::type
  </code></pre>
  
  <p>which then becomes:</p>
  
  <pre><code>std::enable_if&lt;false, bool&gt;::type
  </code></pre>
  
  <p>which then yields an error: there is no <code>type</code> member of <code>std::enable_if&lt;false, bool&gt;</code>, which is indeed the entire point of the <code>enable_if</code> template.</p>
  
  <p>I have two questions. </p>
  
  <ol>
  <li>Why won't SFINAE simply disable the definition of <code>operator==</code> for <code>NotWorkingSimpleVector&lt;int&gt;</code>, like I want it to? Is there some compatibility reason for this? Are there other use-cases I'm missing; does a reasonable counter-argument for this behaviour exist?</li>
  <li>Why does the first class (<code>WorkingSimpleVector</code>) work? It seems to me that the compiler 'reserves judgement': Since the 'ET' parameter is not yet defined, it gives up trying to tell if <code>operator==</code> can exist. Are we relying on the compilers 'lack of insight' to allow this kind of conditionally enabled function (even if this 'lack of insight' is acceptable by the C++ specification)?</li>
  </ol>