编译器在重载两个函数模板时如何决定调用哪个函数:
#include <iostream>
#include <typeinfo>
#ifndef B1
template <typename T1, typename T2>
auto max(T1 a, T2 b) {
std::cout << "auto version called" << std::endl;
return b < a ? a : b;
}
#endif
#ifndef B2
template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b) {
std::cout << "RT version called" << std::endl;
return b < a ? a : b;
}
#endif
template <typename T>
void print(T t) {
std::cout << typeid(t).name() << std::endl;
}
int main() {
auto b = ::max<long double>(4, 7.2);
print(b);
auto c = ::max<int>(4, 7.2);
print(c);
auto d = ::max<double>(4, 7.2);
print(d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用命令构建了代码:
$ g++ -o m1 ./maxdefault4.cpp -std=c++14 -DB1
$ g++ -o m2 ./maxdefault4.cpp -std=c++14 -DB2
Run Code Online (Sandbox Code Playgroud)
这意味着两个函数模板都可以匹配,但为什么没有引起歧义错误。如果使用命令构建:
$ g++ -o m ./maxdefault4.cpp -std=c++14
Run Code Online (Sandbox Code Playgroud)
编译器向我展示了错误:
error: call to 'max' is ambiguous
auto c = ::max<int>(4, 7.2);
Run Code Online (Sandbox Code Playgroud)
我用命令构建了代码:
$ g++ -o m1 ./maxdefault4.cpp -std=c++14 -DB1
$ g++ -o m2 ./maxdefault4.cpp -std=c++14 -DB2这意味着两个函数模板都可以匹配,但为什么没有引起歧义错误。
这是不正确的:当您通过-DB1, or 时-DB2,您只编译了一个模板,因此没有任何歧义的问题,并且编译它并不奇怪。
如果使用命令构建:
$ g++ -o m ./maxdefault4.cpp -std=c++14编译器向我显示错误:...
当您编译两个模板时会发生这种情况,并且更有趣,因为有些调用会编译,而其他调用则不会。
要了解发生了什么,让我们看看当您拥有以下模板时会发生什么:
template <typename T1, typename T2>
auto max(T1 a, T2 b); // #1
template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b); // #2
Run Code Online (Sandbox Code Playgroud)
然后你打电话:
max<double>(4, 7.2);
Run Code Online (Sandbox Code Playgroud)
在这里,编译器将替换提供的参数double,并从参数中推导出剩余的模板参数。
这导致生成:
template<>
double max<double, double>(double a, double b); // #1' from #1
// T1 = double (explicitly specified for 1st template parameter)
// T2 = double (deduced from 2nd function argument)
template<>
double max<double, int, double>(int a, double b); // #2' from #2
// RT = double (explicitly specified for 1st template parameter)
// T1 = int (deduced from 1st function argument)
// T2 = double (deduced from 2nd function argument)
Run Code Online (Sandbox Code Playgroud)
现在使用重载解析来确定#2'参数4, 和的更好匹配7.2,因此#2'被调用。
同样,对于这个调用:
max<int>(4, 7.2);
Run Code Online (Sandbox Code Playgroud)
编译器将替换提供的参数int,并从参数中推导出剩余的模板参数。
这导致生成:
template<>
double max<int, double>(int a, double b); // #1' from #1
// T1 = int (explicitly specified for 1st template parameter)
// T2 = double (deduced from 2nd function argument)
template<>
int max<int, int, double>(int a, double b); // #2' from #2
// RT = int (explicitly specified for 1st template parameter)
// T1 = int (deduced from 1st function argument)
// T2 = double (deduced from 2nd function argument)
Run Code Online (Sandbox Code Playgroud)
现在使用了重载解析,但是#1', 和之间存在歧义#2',因为两者都不比另一个更好(请注意,返回类型在重载解析中不起作用)。这会导致您观察到的错误。