为什么非模板化函数具有相同的名称和参数但返回类型不同是非法的?(但模板功能合法吗?)

use*_*012 11 c++ templates overloading ambiguity

我查看了一些相关的堆栈溢出线程,例如模板函数重载的这种情况,这让我无法理解

函数重载按返回类型?

但似乎都没有给我我正在寻找的答案,至少不是一种容易让我解释的方式.

我的问题归结为:从设计和技术的角度来看,为什么这样做是合法的:

#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();
}
Run Code Online (Sandbox Code Playgroud)

但不是这个:

#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();
}
Run Code Online (Sandbox Code Playgroud)

值得一提的是,如果我在初始化thisFunc和thatFunc时没有明确地给func一个任意模板参数,那么第一个例子将无法编译.两者之间唯一的另一个区别是,第一个有一个完全无关的类型模板化的函数,除了它显然允许我通过返回类型重载.在这种情况下,编译器甚至能够对要调用的函数进行推断,使得c ++中返回类型的函数重载的非法性对我来说有些困惑.无论如何,我猜这是一个巧妙的技巧.

编辑:最困扰我的是不一致性:在我真正考虑通过返回类型进行重载之前,我会想很长很难,但如果想要通过返回类型重载的人的"修复" 只是添加一个无意义的模板参数或显然将函数包装在命名空间内,然后我认为C++应该或多或少地严格关于它认为不明确的东西.是否有令人信服的理由为什么模板和命名空间需要此功能才能正常工作?例如,如果不允许模板在我的示例中消除代码歧义,那么是否存在一些不可行的代码示例?我从语言设计的角度提出要求,而不是编译器合规性的观点.

小智 11

它通常不是无效的:有一种方法可以在返回类型上重载非模板函数.它只会像你做的那样无效.

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();
}
Run Code Online (Sandbox Code Playgroud)

这编译,链接和运行良好.

由于这是有效的并且被实际实现所接受,因此应该清楚的是,没有技术原因导致您的代码无效.不可否认,它需要对名称修改进行一些更改,因为通常非模板函数在修改后的名称中没有返回类型,但它很容易实现.

剩下的是一个合乎逻辑的原因:在返回类型上重载非模板函数几乎肯定是一个错误.它使得函数在正常情况下不可调用,它对常见错误(在一个地方更改声明而忘记其他地方)的诊断非常差,它的使用极其有限,所以就是不要这样做.