Bar*_*rry 9 c++ templates language-lawyer template-argument-deduction c++17
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>
}
Run Code Online (Sandbox Code Playgroud)
gcc的行为对我没有意义 - 如果const T&重载优先U&&于lvalue 的重载const int,为什么rvalue T&&的U&&重载不是首选的重载int?clang对我来说更有意义(没有一个功能比另一个更专业,所以演绎指南胜出).
谁是对的?
我们又在部分订购土地.合成的函数模板参数的类型是
T&& // #1: not a forwarding reference
const T& // #2
U&& // #3: a forwarding reference
Run Code Online (Sandbox Code Playgroud)
前部分排序转换消除了参考性,然后是顶级cv资格,在所有三种情况下都留下了裸露的类型.由此可见,在所有三种情况下,推导都在两个方向上都成功.我们现在离开了[temp.deduct.partial]/9的决胜局:
如果对于给定类型,推导在两个方向上都成功(即,在上面的转换之后类型是相同的)并且P和A都是引用类型(在被替换为上面提到的类型之前):
- 如果参数模板中的类型是左值引用而参数模板中的类型不是,则参数类型不应被视为至少与参数类型一样专用; 除此以外,
- 如果参数模板中的类型比参数模板中的类型更具cv限定(如上所述),则参数类型不应被视为至少与参数类型一样专用.
对于U&&vs T&&,既不适用规则,也没有排序.但是,对于U&&vs const T&,根据第一个项目符号,参数类型U&&不被认为至少与参数类型一样专用const T&.
因此,部分排序发现#2比#3更专业,但发现#1和#3无法区分.GCC是正确的.
也就是说,这可能是部分订购规则的疏忽.类模板推导是我们第一次有"rvalue引用cv-unqualified模板参数而不是转发引用"的东西.以前,在双引用的情况下,转发引用总是会丢失到第二个项目符号的非转发右值引用(因为获得非转发右值引用的唯一方法是,如果你有cv T&&一些非空的cv).