错误的模板函数推导
Wrong template function deduction
以下程序中发生了意外的函数推导。 -
案例一 -
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) {
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 int foo
对于情况 II,我只是从第一个函数中删除了最后一个模板参数 typename。有人可以解释一下这里发生了什么吗?
在这个函数中,
template <typename T, typename>
void foo(T x, int) {
cout << "In int foo\n";
}
你告诉编译器,
- 有2个模板参数。
- return无效。
- 接受两个参数,一个来自
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, typename = void>
void foo(T x, int) {
cout << "In int foo\n";
}
编译器将能够select这个,因为它有一个你没有提供的第二个模板参数的默认值。
以下程序中发生了意外的函数推导。 -
案例一 -
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) {
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 int foo
对于情况 II,我只是从第一个函数中删除了最后一个模板参数 typename。有人可以解释一下这里发生了什么吗?
在这个函数中,
template <typename T, typename>
void foo(T x, int) {
cout << "In int foo\n";
}
你告诉编译器,
- 有2个模板参数。
- return无效。
- 接受两个参数,一个来自
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, typename = void>
void foo(T x, int) {
cout << "In int foo\n";
}
编译器将能够select这个,因为它有一个你没有提供的第二个模板参数的默认值。