This code sample fails to compile due to ambiguous overload resolution
void g(char (&t)[4]) {}
void g(char *t) {}
int main()
{
char a[] = "123";
g(a);
}
and careful reading of overload resolution rules makes it clear why it fails. No problems here.
If we formally transform it into a template version
template <typename T> void g(T (&t)[4]) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
it will continue to behave "as expected" and fail with an ambiguity of the same nature. So far so good.
However, the version below compiles without any issues and choses the second overload
template <typename T> void g(T &t) {}
template <typename T> void g(T *t) {}
int main()
{
char a[] = "123";
g(a);
}
If we comment out the second overload, the first one will be used successfully with T
deduced as char [4]
, i.e. template argument deduction works as expected for the first version, effectively making it equivalent to void g(char (&t)[4])
. So, on the first naive sight this third example should behave the same as the previous two.
Yet, it compiles. What [template] overload resolution rule kicks in in this third case to save the day and direct the compiler to choose the second overload? Why does it prefer array-to-pointer conversion over direct reference binding?
P.S. I find quite a few questions on SO that target very similar issues, but they all seem to differ in some important nuances.