问题描述
以下程序中发生了意外的函数推导。 -
案例一 -
template <typename T,typename>
void foo(T x,int) {
cout << "In int foo\n";
}
template <typename T>
void foo(T x,char) {
cout << "In char foo\n";
}
int main() {
string s = "Hello World";
foo(s,(int) 1);
}
In char foo
案例二 -
template <typename T>
void foo(T x,(int) 1);
}
In int foo
对于案例 II,我只是从第一个函数中删除了最后一个模板参数 typename。有人可以解释一下这里发生了什么吗?
解决方法
在这个函数中,
template <typename T,typename>
void foo(T x,int) {
cout << "In int foo\n";
}
你告诉编译器,
- 有 2 个模板参数。
- 退货无效。
- 采用两个参数,一个来自
T
类型,另一个是int
。 - 然后是函数体。
编译 foo(s,(int) 1);
时,编译器知道 T
的类型是由参数给出的,第二个参数也给出。但是第二个模板参数是未知的。因此,编译器会尝试找到另一个最合适的函数,在本例中为另一个 foo
函数。
这次编译器再次测试它并通过了,因为int
可以隐式转换为char
。这就是为什么它在第一种情况下输出 In char foo
。
第二种情况,由于没有未知类型,最合适的就是第一个函数void foo(T x,int)
。这是因为第二个参数类型是 int
而函数的第二个参数类型也是 int
。
要解决第一种情况下的问题,您可以为模板提供默认类型参数。这样它就知道第二个类型参数,因此可以正常工作。
template <typename T,typename = void>
void foo(T x,int) {
cout << "In int foo\n";
}
,
有点等价于这个,对结果感到惊讶:
void foo(int a,int);
void foo(float b);
int main () {
foo((int) 1); // calls the float version
}
为什么叫浮动版?因为您缺少第二个 int 参数!如果你只发送一个参数,你就不能调用那个版本
只需删除第二个 int
参数使其可调用!
与您的代码相同。您的函数 foo
需要两个模板参数,只能推导出一个,并且您没有将它们发送给编译器。删除一个将使其工作。您还可以设置默认值:
template <typename T,int) {
cout << "In int foo\n";
}
编译器将能够选择该参数,因为它具有您未提供的第二个模板参数的默认值。