我查看了一些相关的堆栈溢出线程,例如 This case of template function overloading eludes my understanding
和
Function overloading by return type?
但这两个似乎都没有给我正在寻找的准确答案,至少不是以一种我容易理解的方式。
我的问题归结为:从设计和技术的角度来看,为什么这样做是合法的:
#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();
}
但不是这个:
#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();
}
值得一提的是,如果我在初始化 thisFunc 和 thatFunc 时没有显式地为 func 指定任意模板参数,第一个示例将无法编译。两者之间唯一的另一个区别是第一个函数由一个完全无关紧要的类型模板化,除了它显然允许我通过返回类型重载。在这种情况下,编译器甚至能够推断调用哪个函数,这让我对 c++ 中通过返回类型重载函数的非法性感到有些困惑。无论如何,我想这是一个绝妙的把戏。
编辑:最让我困扰的是不一致:在我真正考虑通过返回类型重载之前,我会考虑很长时间,但是如果“修复”对于想要的人按返回类型重载是简单地添加一个无意义的模板参数或显然将函数包装在 namespace 中,那么我认为 C++ 应该或多或少地对其认为不明确的内容严格。模板和命名空间需要此功能才能正常工作是否有令人信服的理由?是否有一个理想的代码无法工作的示例,例如,如果不允许模板消除代码歧义,如我的示例所示?我是从语言设计的角度而不是编译器合规性的角度提问。
最佳答案
一般情况下并不是无效的:有一种方法可以在返回类型上重载非模板函数。只有你这样做是无效的。
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();
}
这可以正常编译、链接和运行。
由于这是有效的并且被实际实现所接受,所以应该清楚没有技术原因导致您的代码无效。诚然,这需要对名称修改进行一些更改,因为通常非模板函数在修改后的名称中没有返回类型,但这很容易实现。
剩下的是一个合乎逻辑的原因:在返回类型上重载非模板函数几乎肯定是一个错误。它使该函数在正常上下文中无法调用,它导致对常见错误的诊断非常差(在一个地方更改声明而忘记另一个地方),它的用途极其有限,所以不要这样做。
关于c++ - 为什么非模板函数具有相同的名称和参数但返回类型不同是非法的? (但模板函数合法吗?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32179103/