title: C++11: Overload fails to resolve recursive decltype
body: <p>In the following piece of code, I'm trying to build a lattice of types.  For instance, between <code>float</code> and <code>int</code>, promote the result to <code>float</code>:</p>
  
  <pre><code>float join(float f, int)   { return f; }
  float join(float f, float) { return f; }
  </code></pre>
  
  <p>Then I introduce a <code>wrapper</code> type:</p>
  
  <pre><code>template &lt;typename Inner&gt;
  struct wrapper
  {
    using inner_t = Inner;
    inner_t value;
  };
  </code></pre>
  
  <p>whose behavior with the <code>join</code> operation quite natural:</p>
  
  <pre><code>template &lt;typename Inner1, typename Inner2&gt;
  auto
  join(const wrapper&lt;Inner1&gt;&amp; w1, const wrapper&lt;Inner2&gt;&amp; w2)
    -&gt; wrapper&lt;decltype(join(w1.value, w2.value))&gt;
  {
    return {join(w1.value, w2.value)};
  }
  </code></pre>
  
  <p>It can also be <code>join</code>ed with a "scalar" type:</p>
  
  <pre><code>template &lt;typename Inner1, typename T2&gt;
  auto
  join(const wrapper&lt;Inner1&gt;&amp; w1, const T2&amp; value2)
    -&gt; wrapper&lt;decltype(join(w1.value, value2))&gt;
  {
    return {join(w1.value, value2)};
  }
  </code></pre>
  
  <p>So far, so good, it works.  But then, because in the real case I actually have many more such rules, I'd like to avoid duplicating the number of rules to express the commutativity of the <code>join</code> operation, and therefore, I express that <code>join(scalar, wrapper) := join(wrapper, scalar)</code> (In fact, I'd prefer something like <code>join(v1, v2) := join(v2, v1)</code>, but let's start with something more specific.):</p>
  
  <pre><code>template &lt;typename T1, typename Inner2&gt;
  auto
  join(const T1&amp; value1, const wrapper&lt;Inner2&gt;&amp; w2)
    -&gt; decltype(join(w2, value1))
  {
    return join(w2, value1);
  }
  </code></pre>
  
  <p>this works properly for <code>join(scalar, scalar)</code>, <code>join(wrapper, scalar)</code> and <code>join(scalar, wrapper)</code>.  But then <code>join(wrapper, wrapper)</code> results in an infinite expansions of template functions with both G++ 4.9 and Clang++ 3.5, which I don't understand.</p>
  
  <pre><code>int main()
  {
    int i;
    float f;
    wrapper&lt;float&gt; fr;
    join(f, i);
    join(fr, i);
    join(i, fr);
    join(fr, fr); // Loops.
  }
  </code></pre>
  
  <p>Clang:</p>
  
  <pre><code>clang++-mp-3.5 -std=c++11 bar.cc
  bar.cc:21:5: fatal error: recursive template instantiation exceeded maximum depth of
        256
      join(const wrapper&lt;Inner1&gt;&amp; w1, const T2&amp; value2)
      ^
  bar.cc:29:5: note: while substituting deduced template arguments into function
        template 'join' [with T1 = wrapper&lt;float&gt;, Inner2 = float]
      join(const T1&amp; value1, const wrapper&lt;Inner2&gt;&amp; w2)
      ^
  </code></pre>
  
  <p>GCC:</p>
  
  <pre><code>g++-mp-4.9 -std=c++11 bar.cc
  bar.cc:30:34: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting 'template&lt;class T1, class Inner2&gt; decltype (join(w2, value1)) join(const T1&amp;, const wrapper&lt;Inner2&gt;&amp;) [with T1 = &lt;missing&gt;; Inner2 = &lt;missing&gt;]'
         -&gt; decltype(join(w2, value1))
                                    ^
  bar.cc:30:34:   recursively required by substitution of 'template&lt;class T1, class Inner2&gt; decltype (join(w2, value1)) join(const T1&amp;, const wrapper&lt;Inner2&gt;&amp;) [with T1 = wrapper&lt;float&gt;; Inner2 = float]'
  bar.cc:30:34:   required by substitution of 'template&lt;class T1, class Inner2&gt; decltype (join(w2, value1)) join(const T1&amp;, const wrapper&lt;Inner2&gt;&amp;) [with T1 = wrapper&lt;float&gt;; Inner2 = float]'
  bar.cc:43:18:   required from here
  </code></pre>
  
  <p>I do not understand why overloading does not cut the recursion.  What is going on?  There is probably a possible alternative implementation with (class) template specialization, but I'm not looking for alternative implementations: I'd like to understand what's wrong with this one.  Thanks in advance.</p>