title: Which compiler is correct with respect to template method specialization?
body: <p>I have not kept up with the intricacies of templates so just know enough to be dangerous. However, I ran to a problem (reported by one of our testers) where code compiled properly on Xcode (Clang) and Visual Studio 2019 but the behavior was different and I'm wondering which one was &quot;correct&quot;</p>
  <p>Consider the following simple class:</p>
  <pre><code>template &lt;class T&gt;
  class foo
  {
     void set(int index, T value);
  };
  </code></pre>
  <p>That default templated <strong>set</strong> method worked fine for most values of type <strong>T</strong> but I needed to specialize the behavior for a particular type, call it String.</p>
  <p>So in the associated CPP file, I added the following:</p>
  <pre><code>template &lt;&gt;
  void foo&lt;String&gt;::set(int index,  String value)
  {
     // code here
  };
  </code></pre>
  <p>Under Xcode, this worked perfectly fine. A call to <strong>set</strong> with a second parameter of <strong>String</strong> correctly invoked that specialized template.</p>
  <p>However, the exact same code, compiled with Visual Studio failed, behaved differently. That same call with the <strong>String</strong> parameter just invoked the original <strong>set</strong> rather than than the specialized version.</p>
  <p>I'm assuming that under Xcode, the compiler properly created a call with a signature that matched the specialized version that was available in the CPP file and hence was linked properly.</p>
  <p>So my questions are:</p>
  <ol>
  <li>Why did this work in Xcode but not in Visual Studio</li>
  <li>Which compiler behaved correctly and should the issue be considered a bug in the other compiler?</li>
  </ol>
  <p>Incidentally, I did try creating an explicit signature in the header file:</p>
  <pre><code>template&lt;&gt;
  void foo&lt;String&gt;::set(int index, String value );
  </code></pre>
  <p>and Xcode didn't complain about it and everything still worked.  However, Visual Studio, while not complaining about that header signature, did complain at link time that it couldn't find a matching implementation and so:</p>
  <ol start="3">
  <li>Why did that not work?</li>
  </ol>
  <p>While I did find a way to do it that worked for both compilers (essentially putting inline versions in the header file, I would really like to understand why this problem happened.</p>
  <p>I thank people in advance.</p>
  <p>Edit: bllow is a real example I just put together. This compiles and runs perfectly fine under Xcode (in particular, the string specialization is correctly called for variable g) but fails to link in Visual Studio 2019 with the following error</p>
  <p>(
  public: void __cdecl Foo&lt;class std::basic_string&lt;char,struct std::char_traits,class std::allocator &gt; &gt;::print(int,class std::basic_string&lt;char,struct std::char_traits,class std::allocator &gt;)&quot; (?print@?$Foo@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QEAAXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function main) referenced in function main
  )</p>
  <pre><code>    Classes.h
      ---------
      #pragma once
  
      #include &lt;iostream&gt;
      #include &lt;string&gt;
  
      template &lt;class T&gt;
      class Foo
      {
         public:
            void print(int index, T value)
               {
                  std::cout &lt;&lt; &quot;Using implicit template\n&quot;;
               }
      };
  
  
  
  
      Classes.cpp
      -----------
  
      #include &quot;Classes.h&quot;
  
  
      template&lt;&gt;
      void Foo&lt;std::string&gt;::print(int i, std::string xyz)
      {
         std::cout &lt;&lt; &quot;Using explicit String template\n&quot;;
      }
  
  
  
      Main.cpp
      --------
  
      #include &lt;string&gt;
      #include &lt;iostream&gt;
  
      #include &quot;Sub/Classes.h&quot;
  
      //==============================================================================
      int main (int argc, char* argv[])
      {
  
          Foo&lt;double&gt; f;
          
          f.print(1, 2.0);
          
          Foo&lt;std::string&gt; g;
          
          g.print(1, &quot;abc&quot;);
  
          return 0;
      }
  </code></pre>