c ++中的参考解释

时间:2013-06-04 05:44:59

标签: 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

    int b = 10;
    inc2(b); // b remains 10
}

替换后我们有

void inc1(int& x)
{
    int& y = x; // reference to x
    ++y; // increments x
}

void inc2(int& x)
{
    int y = x; // copy of x
    ++y; // increments the copie
}

inc1中,x的类型为int&,因为int&T&&都是引用,但两者都不是r值。

同样,在inc2中,x的类型为int&,因为int&T&都是引用,但两者都不是r值

我的问题是关于y:为什么在inc1y的类型为int&,而在inc2y是输入int

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

2 个答案:

答案 0 :(得分:14)

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

另一方面,在inc2中,编译器必须推导T,使T &与您提供的参数类型匹配,这仍然是int &。假设T只是int,这是最容易做到的,那么就是你得到的本地y类型。


回复一些评论(同时已被删除):如果你有一个预定义参数类型的函数,例如

inc3(int x) { /*...*/ }

然后,当你打电话给这个时,例如如inc3(a),编译器将对参数应用任何必要的隐式转换以使其适合。在inc3(a)的情况下,这意味着将aint &(在左值意义上)转换为int(在右值意义上) - 这称为左值 - to-rvalue转换和有效的隐式转换。它基本上等于将变量a转换为它当时所代表的值。

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

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

答案 1 :(得分:7)

S14.8.2.1 [temp.deduct.call]说:

  

模板参数推导是通过比较每个函数模板参数类型(称之为P)来完成的   调用的相应参数的类型(称之为A),如下所述。

所以,我们试图找出一个给定类型为int的P的P。

S14.8.2.3继续:

  

如果P是cv限定类型,则类型推导将忽略P类型的顶级cv限定符。如果P是a   引用类型,P引用的类型用于类型推导。如果P是对cv-nonqualified模板参数的rvalue引用,并且参数是左值,则使用类型“对A的左值引用”代替A来进行类型推导。 [例如:

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
  

-end example]

您的调用与示例中的f(i)类似 - 它实例化f<int&>(int&)形式的函数...即Tint&,这就是为什么{{ 1}}创建对T y = x的引用。

另见Scott Meyers在http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

的页面