It is well known that ordinary functions that differ only in their return type cannot be overloaded in C .
But this limitation does not hold for overloaded function templates, for example:
int f(auto) { return 1; }
auto f(auto) { return 2; }
All compilers accept it, demo: https://gcc.godbolt.org/z/qj73Mzehd
Why does the language make such exception for the templates?
If the return type of the overloaded functions differ, then it will be possible to select one of the functions using the cast to expected function type. Surprisingly, Clang allows one to resolve the ambiguity even if the return type is actually the same, for example:
((int(*)(int))f)(3);
selects
int f(auto) { return 1; }
Demo: https://gcc.godbolt.org/z/snfvbq1ME
Is Clang wrong here?
CodePudding user response:
Why does the language make such exception for the templates?
You mean this?
signature [defns.signature.templ]
⟨function template⟩ name, parameter-type-list, enclosing namespace (if any), return type, template-head, and trailing requires-clause (if any)
Yes, the return type is there. It's what always made possible things like
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type foo(T&);
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type foo(T&);
SFINAE is why the return type is included in the signature. Substitution failure is possible in the return type, so it's part of signature comparison. You can still potentially generate two conflicting specializations to overload on (in the general case, not in the example), but the templates would be different.