以下代码:
class A {};
template <typename T> void f(T& a) {}
template <typename T> void f(T&& a) {}
int main() {
A a;
f(a);
}
clang ++将调用绑定到第一个重载,而g ++报告模糊调用。哪一个采取了正确的行动?
答案 0 :(得分:6)
gcc 4.9.0 20140302和clang 3.5(trunk 202594)都正确选择了第一个版本。正如hvd友好地给了我the references in comments:
这是一个微妙的问题,有a defect report,
4.9之前的gcc实现实现了早期的缺陷,请参阅Template overload resolution ambiguous for T&&
versus T&
标准中的相应部分是 14.8.2.4 [temp.deduct.partial] ,第9段:
对于给定类型,如果在两个方向上推导成功(即,上述转换后类型相同),并且
P
和A
都是引用类型(在替换为类型之前)如上所述):
- 如果参数模板中的类型是左值引用而参数模板中的类型不是,则参数类型被认为比其他类型更专业;否则,
- 如果参数模板中的类型比参数模板中的类型更具cv限定(如上所述),则认为参数类型比另一个更专业;否则,
- 两种类型都不比另一种更专业。
顺便说一下,观看The Universal Reference/Overloading Collision Conundrum视频为什么在通用引用上重载是一个坏主意。简而言之,请考虑以下示例:
#include <iostream>
#include <utility>
struct A { bool guts_stolen; };
void steal_guts(A&& a) {
a.guts_stolen = true;
}
template <typename T> void f(const T& a) {
// ^^^^^ note the const!
std::cout << "T&\n";
}
template <typename T> void f(T&& a) {
std::cout << "T&&\n";
steal_guts(std::move(a));
}
int main() {
A a{ false };
f(a);
std::cout << "Guts stolen? " << std::boolalpha << a.guts_stolen << std::endl;
}
如果您运行程序,它将打印
T&&
Guts stolen? true
通过查看A a{ false }; f(a);
,完全不是您所期望的。