c++中的引用解释
Reference interpretation in c++
考虑以下代码:
#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
:为什么在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 [temp.deduct.call]说:
模板实参推导是通过比较每个函数模板形参类型(称之为p)与调用的对应实参的类型(称之为A),如下所述。
所以,我们试着在给定类型为int
的a的情况下计算p
S14.8.2.3继续说:
如果p是限定cv的类型,则忽略p类型的顶级cv限定符进行类型推导。如果P是a引用类型,则使用P所引用的类型进行类型推导。如果P是对cv不限定模板形参的右值引用,且实参是左值,则使用"对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&)
的函数…也就是说,T
是int&
,这就是为什么T y = x
创建了对x
的引用。
参见Scott Meyers的主页http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 请解释"函数1(p1,p2,p3);"的输出
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 隐式重新解释引用时强制转换,没有警告/错误
- 解释通过从函数引用返回数组的语法
- 寻找有关为什么此C++代码在没有引用的情况下不起作用的解释
- 引用变量何时合适,为什么?你能解释一下实际的语法和位置吗?
- 有人可以解释一下通过此代码的值/引用传递的过程
- 通过重新解释强制转换创建无效引用
- 有人能解释一下这些编程术语吗:引用语义,非线性可变状态
- 为什么非常量指针上的常量引用被解释为常量指针
- 有人能解释一下这个C++引用的用法吗
- 需要解释才能理解一个引用的例子
- c++中的引用解释
- C#中引用类型的内存方面的显式强制转换解释
- 指向基的解引用指针的c++ ISO标准解释
- 如何防止size_t被解释为引用