C++ c+中的参考解释+;

C++ c+中的参考解释+;,c++,c++11,C++,C++11,考虑以下代码: #include <iostream> template<typename T> void inc1(T&& x) { T y = x; ++y; } template<typename T> void inc2(T& x) { T y = x; ++y; } int main() { int a = 10; inc1(a); // a is now 11

考虑以下代码:

#include <iostream>

template<typename T>
void inc1(T&& x)
{
    T y = x;
    ++y;
}

template<typename T>
void inc2(T& x)
{
    T y = x;
    ++y;
}

int main()
{
    int a = 10;
    inc1(a); // a is now 11

    int b = 10;
    inc2(b); // b remains 10
}
inc1
中,
x
属于
int&
类型,因为
int&
T&
都是参考值,但不是都是r值

类似地,在
inc2
中,
x
属于
int&
类型,因为
int&
T&
都是引用,但不是都是r值

我的问题是关于
y
:为什么在
inc1
中,
y
int&
类型,而在
inc2
中,
y
int
类型


我在gcc 4.8.1和microsoft v110和v120_ctp上都观察到了这一点。

在这两个函数调用中,传递给函数的是
int&
(意思是:“类型为
int
的左值”)。因此,在声明
inc1
时,编译器必须推断
T
,以便
T&&
与您提供的参数匹配,即
int&
。唯一的方法是假设
T
int&
,因为
T&&
int&&
,这相当于
int&
。因此
T
变为
int&
,并且本地
y
被声明为这样

另一方面,在
inc2
中,编译器必须推断
T
,以便
T&
与您提供的参数类型匹配,该参数类型仍然是
int&
。通过假设
T
只是
int
,最容易做到这一点,因此这就是本地
y
的类型


回复一些注释(同时被删除):如果您有一个具有预定义参数类型的函数,例如

inc3(int x) { /*...*/ }
然后,当您将其称为
inc3(a)
时,编译器将对参数应用任何必要的隐式转换以使其适合。在
inc3(a)
的情况下,这意味着将
a
int&
(左值意义上)转换为
int
(右值意义上)–这称为左值到右值转换和有效的隐式转换。它基本上相当于将变量
a
转换为它当时表示的值

但是,当您声明一个模板时,例如问题中的
inc1
inc2
,并且函数参数是根据模板参数定义的,那么编译器将不会(或者不仅仅)尝试对参数应用隐式转换以使其适合。相反,它将选择参数类型参数
T
,以便与您提供的参数类型匹配。这方面的规则很复杂,但是在
T&&
类型参数声明的情况下,它们的工作方式如上所述。(在纯
T
参数声明的情况下,左值参数仍将进行左值到右值的转换,
T
将被推断为
int
,而不是
int&


这就是为什么当
int&
是右值引用时,
T&
(其中
T
是模板参数)不一定是右值引用。相反,它是将
T
拟合到提供的参数所得到的结果。因此,在这种情况下,表达式
T&&
被称为通用参考(与左值或右值参考相反)–它是一种根据需要变成左值或右值参考的参考。

S14.8.2.1[临时扣减调用]表示:

通过将每个函数模板参数类型(称为p)与 调用的相应参数的类型(称为A),如下所述

所以,我们试图计算出一个p,给定一个
int
类型

S14.8.2.3继续:

如果p是cv限定类型,则p类型的顶级cv限定符将被忽略以进行类型推断。如果P是a 引用类型,P引用的类型用于类型推断。如果P是对cv非限定模板参数的右值引用,且参数是左值,则类型“对a的左值引用”将代替类型演绎。[示例:


template int f(T&&);//为什么说我们传递一个
int&
?这很明显吗?@perreal是的。传递的参数是声明为
int
的变量:
int a=10;
int b=10;
。当这些变量用作函数调用的参数时,它们的类型是
int&
(即,它们是左值引用)。更正我之前的评论:这些变量的类型确实是
int&
,因此它们是左值(不是左值引用。该术语仅适用于声明为
a
b
引用的新变量)。你没有传递一个
int&
,你传递的是一个
int
!变量的类型是由它们的声明确定的,不依赖于使用它们的上下文。此外,你把表达式的值和表达式的类型混在了一起。正确的答案是Tony D的答案。@MWid我的推理没有说明任何关于e角色
const
在模板参数类型推导中起作用。
inc3(int x) { /*...*/ }
template <class T> int f(T&&);         // <--- YOUR TEMPLATE IS LIKE THIS
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)  // <--- YOUR CALL IS LIKE THIS
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
               // would bind an rvalue reference to an lvalue