title: Why do `SFINAE` (std::enable_if) uses bool literals instead of `true_t` / `false_t` tag classes?
body: <p>I am trying to learn about <code>SFINAE</code> (i am following this <a href="https://eli.thegreenplace.net/2014/sfinae-and-enable_if/#id5" rel="nofollow noreferrer">tutorial</a>), but there are some... "design choices" I do not understand and, as such, I find them confusing.</p>
  
  <p>Let's assume I have a situation like this (included re-implementation of <code>std::enable_if</code> is there just to demonstrate how I understand <code>enable_if</code>)</p>
  
  <pre><code>// A default class (class type) declaration. Nothing unusual.
  template &lt;bool, typename T = void&gt;
  struct enable_if
  {}; 
  
  // A specialisation for &lt;true, T&gt; case. I understand 'why-s' of this. 
  // -- 'why-s': if I attempt to access 'enable_if&lt;false, T&gt;::type' (which does not exist) I will get a substitution failure and compiler will just "move-on" trying to match "other cases".
  template &lt;typename T&gt;
  struct enable_if&lt;true, T&gt; {
      typedef T type;
  };
  
  // Here lies my problem:
  template &lt;class T,
           typename std::enable_if&lt;std::is_integral&lt;T&gt;::value,T&gt;::type* = nullptr&gt;
  void do_stuff(T&amp; t) { /* do stuff */ };
  </code></pre>
  
  <p><br><strong>(1)</strong> The very 1st thing I have a "problem" with, is <code>bool</code> literal (<code>true</code>/<code>false</code>). I understand they are correct and templates can accept compile-time constant values of primitive data types (plain-old-data types) but if I were tasked to design the <code>enable_if</code> "mechanisms" instead of using <code>true</code>/<code>false</code> I would create a tag classes <code>true_t</code>(or <code>True</code>) and <code>false_t</code> (or <code>False</code>) as follows:</p>
  
  <pre><code>class true_t {}; // or True
  
  class false_t {}; // or False
  
  template&lt;typename T&gt;
  class is_integral // just to have "something" to use with "enable_if"
  {
      using result = false_t;
  };
  
  template&lt;&gt;
  class is_integral&lt;int32_t&gt; // same with all other int types
  {
      using result = true_t;
  };
  
  template &lt;typename B, typename T = void&gt;
  struct enable_if
  {}; 
  
  template &lt;typename T&gt;
  struct enable_if&lt;true_t, T&gt;
  {
      using type = T;
  };
  </code></pre>
  
  <p><br><strong>(2)</strong> The second thing I find redundant is the need to specify <code>typename T</code> template parameter. Wouldn't it be easier / better to just implement <code>enable_if</code> as follows:</p>
  
  <pre><code>template &lt;typename B&gt;
  struct enable_if
  {}; 
  
  template &lt;&gt;
  struct enable_if&lt;true_t&gt;
  {
      using type = void; // the 'type' exists therefore substitution failure will not occur. 
  };
  </code></pre>
  
  <p><br><strong>I am well aware that all my propositions are extremely inferior to the currently existing solutions</strong>, but I don't understand why... What portion of the functionality (important functionality) of current <code>SFINAE</code> did i shave off? (Not even realizing it...)</p>
  
  <hr>
  
  <p>I know that, on this site, I am obligated to ask a single question within a... single "question-post-like" format, but if you find it acceptable could I also ask what will this syntax:</p>
  
  <pre><code>std::enable_if&lt;/* ... */&gt;::type* = nullptr
  </code></pre>
  
  <p>accomplish? It's beyond my understanding right now...</p>