As per this document, which says that[emphasis mine]:
The return type of a function has no effect on function overloading, therefore the same function signature with different return type will not be overloaded. Example: if there are two functions: int sum() and float sum(), these two will generate a compile-time error as function overloading is not possible here.
It's amazing that this code snippet works!
#include <type_traits>
#include <iostream>
template <typename T>
T foo(){return T{};}
template<>
int foo(){std::cout << "int" << std::endl; return int{};}
template<>
double foo(){std::cout << "double" << std::endl; return double{};}
int main() {
foo<int>();
foo<double>();
foo<bool>();
}
You see, the code snippet below does not compile indeed(If you have a question in it, please see the quotation at the beginning of the post):
#include <type_traits>
#include <iostream>
int foo(){std::cout << "int" << std::endl; return int{};}
double foo(){std::cout << "double" << std::endl; return double{};}
int main() {
}
CodePudding user response:
In the first snippet, you're providing two specializations of the more general primary function template foo<T>
. In particular, you have provided specializations for T=int
and T=double
meaning we'll have foo<int>
and foo<double>
which are different from each other.
So in the 1st snippet there is no function overloading since the name are not the same in the first place. One is foo<int>
and other is foo<double>
.
From function overloading 11.3.5.5
A single name can be used for several different functions in a single scope; this is function overloading.
More importantly, note that specializations instantiate a template; they do not overload it. As a result, specializations do not affect function matching.
Consider the following examples to illustrate the point:
Example 1
template <typename T>
T foo(T a, T b){return T{};}
template <>
int foo(int a, int b){return 4;}
int main()
{
foo(5, 7.0); // error: no matching function for call to ‘foo(int, double)’
}
Example 2
template <typename T>
T foo(T a, T b){return T{};}
int foo(int a, int b){return 4;}
int main()
{
foo(5, 7.0); // works fine
}
On the other hand, in the 2nd snippet since the name of the function is the same, thus it is function overloading and we can't overload ordinary function just on the return type.
From Overloadable declarations
Function declarations that differ only in the return type, the exception specification, or both cannot be overloaded.