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

时间:2015-08-24 09:42:58

标签: c++ templates overloading ambiguity

我查看了一些相关的堆栈溢出线程,例如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 ++中返回类型的函数重载的非法性对我来说有些困惑。无论如何,我猜这是一个巧妙的技巧。

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

1 个答案:

答案 0 :(得分: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();
}

这可编译,链接并运行正常。

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

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