How to mismatch function templates that differ only in return type?

I noticed that there is an asymmetry between the signature used to distinguish the unique functions of the template and the signature used to highlight the unique functions (including those that were created from the functions of the template).

In particular, template functions that differ only in the return type are considered unique, while functions that differ in only the return type are considered redundant.

Therefore, I have a corresponding question on how to eliminate the ambiguity between function templates that differ only in the return type at the time of instantiation:

#include <iostream> template<typename T> long foo(T) { std::cout << "long" << std::endl; return 0; } template<typename T> char foo(T) { std::cout << "char" << std::endl; return '\0'; } int main() { double d = 0.0; long n = foo(d); // <- Ambiguous: How to specify the template function to use? } 

In the above code, creating a template function foo ambiguous precisely because of the asymmetry that I just mentioned. Having two definitions of template functions is legal, but instantiating is illegal, although the return type is indicated on the same line of code.

I ask this question solely for theoretical learning purposes. Perhaps this construction of code in real life will be a sign of poor design. Perhaps this will never happen in real life. In addition, I can present various ways to overcome this problem by changing template definitions (or by making other changes).

However, I would still like to know if by keeping the template definitions intact, the ambiguity between the two template functions can be removed at the time of instantiation.

+5
source share
2 answers

When using templates, you can actually eliminate two different overloads. This is not very, but it works:

 long n = static_cast<long(*)(double)>(&foo)(d); 
+6
source

If you really need to have two function templates with the same names, the same list of parameters, but with different types of return values, you have no choice but to distinguish them by specifying the type of the parameter returned by the template:

 template <typename R, typename T> R foo(T); 

IIRC there is a specialized specification of function templates in C ++ 11, although I could not find anything about this in the standard. If there is, this should work:

 //partial function template specializations: C++11 only! template <typename T> long foo<long, T>(T) { std::cout << "long" << std::endl; return 0; } template<typename T> char foo<char, T>(T) { std::cout << "char" << std::endl; return '\0'; } 

Or else, in C ++ 03:

 template <typename R, typename T> struct FooImpl; template <typename T> struct FooImpl<long, T> { static long doIt(T) { std::cout << "long" << std::endl; return 0; } }; template <typename T> struct FooImpl<char, T> { static char doIt(T) { std::cout << "char" << std::endl; return '\0'; } }; template <typename R, typename T> R foo(T t) { return FooImpl<R, T>::doIt(t); } 

In both cases, your main file will look like this:

 int main() { double d = 0.0; long n = foo<long>(d); // specify the return type only auto c = foo<char>(n); } 
+1
source

All Articles