gcc 8.0.0和clang 5.0.0对此计划的行为持不同意见:
#include <iostream>
template <typename T>
struct A {
A(const T&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
A(T&&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};
template <typename U> A(U&&) -> A<double>;
int main() {
int i = 0;
const int ci = 0;
A a1(0); // both say A<double>
A a2(i); // both say A<double>
A a3(ci); // gcc says A<int>, clang says A<double>
}
gcc的行为对我没有意义 - 如果const T&
重载优先于左值U&&
的{{1}}重载,为什么不是&#39;对于右值const int
,T&&
重载优先于U&&
重载? clang对我来说更有意义(没有一个功能比另一个更专业,所以演绎指南获胜)。
谁对吗?
答案 0 :(得分:7)
我们再次部分订购土地。合成的函数模板参数的类型是
T&& // #1: not a forwarding reference
const T& // #2
U&& // #3: a forwarding reference
预偏序转换strips away referenceness以及之后的top-level cv-qualification,在所有三种情况下都留下了裸露类型。由此可见,在所有三种情况下,推导都在两个方向上都成功。我们现在离开了[temp.deduct.partial]/9的决胜局:
如果对于给定类型,扣除在两个方向上都成功(即, 在上述转换之后,类型是相同的,并且P和A都是相同的 是引用类型(在被引用的类型替换之前) 上面):
- 如果参数模板中的类型是左值 引用和参数模板中的类型不是, 参数类型不被认为至少与 参数类型;否则,
- 如果参数模板中的类型 比参数模板中的类型更具cv限定(如 如上所述,参数类型至少不被认为是 与参数类型一样专门。
对于U&&
vs T&&
,这两条规则都不适用且没有排序。但是,对于U&&
vs const T&
,根据第一个项目符号,参数类型U&&
不会被认为至少与参数类型const T&
一样专业。
部分排序因此发现#2比#3更专业,但发现#1和#3无法区分。海湾合作委员会是正确的。
也就是说,这可能是部分订购规则的疏忽。类模板推导是我们第一次对cv-unqualified模板参数进行&#34; rvalue引用,该参数不是转发引用&#34;事情。以前,在双引用的情况下,转发引用总是会丢失到第二个项目符号的非转发右值引用(因为你获得非转发右值引用的唯一方法是,对于某些非空{cv T&&
{1}})。