简体   繁体   中英

Why is it illegal for non-templated functions to have same name and arguments but different return types? (but legal for template functions?)

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM