For a class with expression templates, I stumbled over the following error during return type deduction of overloaded operators. The example below illustrates the error:
template < typename T >
struct A_Number {
T x;
};
// TAG1
template < typename T >
A_Number< T >
operator+(const A_Number< T > &a, const A_Number< T > &b)
{
return {a.x + b.x};
}
// TAG2
template < typename T, typename S >
A_Number< T >
operator+(const A_Number< T > &a, const S &b)
{
return {a.x + b};
}
// TAG3
template < typename T, typename S >
auto
operator+(const S &b, const A_Number< T > &a) -> decltype(a + b)
// ^^^^^
{
return a + b;
}
int
main(void)
{
auto x1 = A_Number< int >{1};
auto x2 = A_Number< int >{1};
auto res1 = x1 + 1; // instantiates TAG2
auto res2 = 1 + x1; // instantiates TAG3, TAG2
auto res3 = x1 + x2; // error, tries to match TAG3
return EXIT_SUCCESS;
}
When trying to compile this with g++-5 or clang++, I get this error
fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
operator+(const S &b, const A_Number< T > &a) -> decltype(a + b)
Apparently, the compilers try to match version TAG3, although a better match (TAG1) is available. When trying to match, they try to deduce the return type which seems to cause recursive instantiations of TAG3. Why does the return type deduction not see the other (better matching) overloads? And is it correct behavior to deduce the return type even though another overloaded template function has a better matching signature?
Interestingly, this error evaporates in thin air, when omitting the return type altogether and compiling with c++14
, like so:
// TAG3
template < typename T, typename S >
auto
operator+(const S &b, const A_Number< T > &a) // C++14
{
return a + b;
}
Admittedly, it's an academic question because workarounds are possible. But can anybody elucidate whether this behavior is standard conforming or a compiler bug?
This is actually correct behavior on the compilers' part. Overload resolution has two steps, from [over.match]:
The candidate functions for
x1 + x2
are:So ok, we need to determine what the return type is for
TAG3
first, before we pick the best viable candidate. Now,operator+
is a dependent name here, as it depends on two template arguments. So according to [temp.dep.res]:So to resolve the return type of
TAG3
, we need to do lookup and overload resolution ona+b
. That gives us our same three candidates again (the first two found the usual way,TAG3
not-so-helpfully being found again via ADL), so around and around we go.Your solutions are:
TAG3
. That stops the merry-go-round, and we will start with our three viable candiates, of whichTAG1
is most specialized so it will be selected as the best viable candidate.Prevent
TAG3
from being instantiated ifS
isA_Number<T>
. For instance, we can create a type trait forA_Number
:That will compile even in C++11.