11

I looked a few related stack overflow threads such as This case of template function overloading eludes my understanding

and

Function overloading by return type?

but neither seem to give me precisely the answer I'm looking for, at least not in a way that has been easy for me to interpret.

My question boils down to this: why, from both a design and technical standpoint, is it legal to do this:

#include <iostream>

using namespace std;

template<class T>
void func(){
    cout << "Compiler inferred from void return value!\n";
}

template<class T>
int func(){
    cout << "Compiler inferred from int return value!\n";
    return 0;
}

int main(){
    void (*thisFunc)()=func<int>;
    int (*thatFunc)()=func<int>;
    thisFunc();
    thatFunc();
}

But not this:

#include <iostream>

using namespace std;

void func(){
    cout << "You won't see this because it won't compile!\n";
}

int func(){
    cout << "Nor this one!\n";
    return 0;
}

int main(){
    void (*thisFunc)()=func;
    int (*thatFunc)()=func;
    thisFunc();
    thatFunc();
}

It is worth mentioning that the first example won't compile if I do not explicitly give func an arbitrary template parameter when initializing thisFunc and thatFunc. The only other difference between the two is that the first one has func templated by a type which is completely immaterial, except that it is apparently allowing me to overload by return type. The compiler is even able to make an inference in that case on which function to call, making the illegality of function overloading by return type in c++ somewhat baffling to me. In any case, it's a neat trick I guess.

EDIT: The thing that bothers me the most is the inconsistency: I would think very long and hard before I genuinely considered overloading by return type, but if the "fix" for someone who wants to overload by return type is to simply add a meaningless template parameter or apparently wrap the functions inside namespaces, then I would think either C++ should either more or less strict about what it considers ambiguous. Is there a compelling reason why templates and namespaces need this functionality to work correctly? Is there an example of desirable code that could not work if, for instance, templates were not allowed to disambiguate code as in my example? I am asking from a language design standpoint, not a compiler compliance standpoint.

Community
  • 1
  • 1
user1609012
  • 191
  • 8
  • For template, I think it is to allow SFINAE or return type. – Jarod42 Aug 24 '15 at 09:52
  • 3
    You are not really overloading on return type, but using SFINAE so select the only possible template instantiation for each function pointer. When you use `func`, in each declaration there is only one template where the substitution works, but it is not an error for the other one to fail. It is just ignored. – Bo Persson Aug 24 '15 at 11:33

1 Answers1

11

It's not invalid in general: there is a way to overload non-template functions on return type. It's only invalid the way you're doing it.

namespace A {
  void func() {}
}
namespace B {
  int func() { return 0; }
}
using A::func;
using B::func;
int main(){
  void (*thisFunc)()=func;
  int (*thatFunc)()=func;
  thisFunc();
  thatFunc();
}

This compiles, links and runs fine.

Since this is valid and is accepted by real implementations, it should be clear that there is no technical reason why your code couldn't be valid. Admittedly it would require some changes to name mangling, as typically non-template functions don't have their return type in the mangled name, but it's easily doable.

What's left is a logical reason: overloading non-template functions on return type is almost certainly a mistake. It makes the function uncallable in normal contexts, it makes for extremely poor diagnostics for common errors (changing a declaration in one place and forgetting the other place), it has extremely limited use, so just don't do it.