首先,这个问题已经被其他人问过,参见this和this,但是(我认为)他们都没有提供令人满意的答案。
根据cppreference,
在开始推算之前,对P和A进行如下调整:
- 如果 P 不是引用类型, a) 如果A是数组类型,则将A替换为数组到指针转换得到的指针类型; b) 否则,如果A是函数类型,则将A替换为函数到指针转换得到的指针类型; c) 否则,如果 A 是 cv 限定类型,则推导时将忽略顶级 cv 限定符:
- 如果 P 是 cv 限定类型,则推导时将忽略顶级 cv 限定符。
- 如果P是引用类型,则使用引用类型进行推导。
- 如果 P 是对 cv 不合格模板参数的右值引用(所谓的转发引用),并且对应的函数调用参数是左值,则使用对 A 的类型左值引用代替 A 进行推导
在这些转换之后,推导过程如下所述(参见从类型推导部分),并尝试找到这样的模板参数,使推导的 A(即,在上面列出的调整和替换推导的模板参数之后的 P) ) 与变换后的 A 相同,即经过上述调整后的 A。
使用这个规则,我们看下面的代码,其中
type_name
来自这个答案:
template<typename T>
void foo(T && t) {
std::cout << type_name<T>();
}
int main() {
int a = 1;
foo(std::move(a)); // int, not int&&
}
由规则3可知,由于P =
T &&
是引用类型,因此使用引用类型T
进行推导,即推导出A为T
。
A 是
std::move(a)
的类型,它是 int &&
类型的右值。没有适用的变换,因此变换后的 A 是 int &&
。
为了使推导的 A 与变换后的 A 相同,我们将有
T = int &&
。
但是上面的代码显示了
T = int
。这是 cppreference 的不准确,还是我的误解?