涉及通用参考的过载分辨率

时间:2014-03-07 10:56:09

标签: c++ gcc c++11 clang language-lawyer

以下代码:

class A {};

template <typename T> void f(T& a) {}
template <typename T> void f(T&& a) {}

int main() {
    A a;
    f(a);
}

clang ++将调用绑定到第一个重载,而g ++报告模糊调用。哪一个采取了正确的行动?

1 个答案:

答案 0 :(得分:6)

gcc 4.9.0 20140302和clang 3.5(trunk 202594)都正确选择了第一个版本。正如hvd友好地给了我the references in comments

  

对于给定类型,如果在两个方向上推导成功(即,上述转换后类型相同),并且PA都是引用类型(在替换为类型之前)如上所述):
       - 如果参数模板中的类型是左值引用而参数模板中的类型不是,则参数类型被认为比其他类型更专业;否则,
       - 如果参数模板中的类型比参数模板中的类型更具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);

完全不是您所期望的。