title: Conversion operator template specialization
body: <p>Here's a largely academic exercise in understanding conversion operators, templates and template specializations.  The conversion operator template in the following code works for <code>int</code>, <code>float</code>, and <code>double</code>, but fails when used with <code>std::string</code>... sort of.  I've created a specialization of the conversion to <code>std::string</code>, which works when used with initialization <code>std::string s = a;</code>, but fails when used with a cast <code>static_cast&lt;std::string&gt;(a)</code>.</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  #include &lt;sstream&gt;
  
  class MyClass {
       int y;
  public:
      MyClass(int v) : y(v) {}
      template &lt;typename T&gt;
      operator T() { return y; };
  };
  
  template&lt;&gt;
  MyClass::operator std::string() {
      std::stringstream ss;
      ss &lt;&lt; y &lt;&lt; " bottles of beer.";
      return ss.str();
  }
  
  int main () {
      MyClass a(99);
      int i    = a;
      float f  = a;
      double d = a;
      std::string s = a;
  
      std::cerr &lt;&lt; static_cast&lt;int&gt;(a) &lt;&lt; std::endl;
      std::cerr &lt;&lt; static_cast&lt;float&gt;(a) &lt;&lt; std::endl;
      std::cerr &lt;&lt; static_cast&lt;double&gt;(a) &lt;&lt; std::endl;
      std::cerr &lt;&lt; static_cast&lt;std::string&gt;(a) &lt;&lt; std::endl; // Compiler error
  }
  </code></pre>
  
  <p>The above code generates a compiler error in g++ and icc, both complaining that no user-defined conversion is suitable for converting a <code>MyClass</code> instance to a <code>std::string</code> on the <code>static_cast</code> (C-style casts behave the same).</p>
  
  <p>If I replace the above code with explicit, non-template versions of the conversion operator, everything is happy:</p>
  
  <pre><code>class MyClass {
      int y;
  public:
      MyClass(int v) : y(v) {}
      operator double() {return y;}
      operator float()  {return y;}
      operator int()    {return y;}
      operator std::string() {
          std::stringstream ss;
          ss &lt;&lt; y &lt;&lt; " bottles of beer.";
          return ss.str();
      }
  };
  </code></pre>
  
  <p>What is wrong with my template specialization for <code>std::string</code>?  Why does it work for initialization but not casting?</p>
  
  <p>Update:</p>
  
  <p>After some template wizardry by @luc-danton (meta-programming tricks I'd never seen before), I have the following code working in g++ 4.4.5 after enabling experimental C++0x extensions.  Aside from the horror of what is being done here, requiring experimental compiler options is reason enough alone to <strong>not</strong> do this.  Regardless, this is hopefully as educational for others as it was for me:</p>
  
  <pre><code>class MyClass {
      int y;
  public:
      MyClass(int v) : y(v) {}
  
      operator std::string() { return "nobody"; }
  
      template &lt;
          typename T
          , typename Decayed = typename std::decay&lt;T&gt;::type
          , typename NotUsed = typename std::enable_if&lt;
              !std::is_same&lt;const char*, Decayed&gt;::value &amp;&amp;
              !std::is_same&lt;std::allocator&lt;char&gt;, Decayed&gt;::value &amp;&amp;
              !std::is_same&lt;std::initializer_list&lt;char&gt;, Decayed&gt;::value
            &gt;::type
      &gt;
      operator T() { return y; }
  };
  </code></pre>
  
  <p>This apparently forces the compiler to choose the conversion <code>operator std::string()</code> for <code>std::string</code>, which gets past whatever ambiguity the compiler was encountering.</p>