C++ 斯科特·迈尔斯论右旋价值

C++ 斯科特·迈尔斯论右旋价值,c++,c++11,move-semantics,rvalue-reference,C++,C++11,Move Semantics,Rvalue Reference,我观看了这部电影,从中我学到了关于右值引用、移动和转发的大部分知识。有一次,他说的是右值,而不是变量的类型,他说的是“右值独立于类型” 我知道你可以有这样的方法: void func(MyType&& rRef) { // Do domething with rRef... } 这里的rRef是一个左值,因为它可以被识别,它的地址可以被获取,等等,即使它的类型是MyType& 但是右值不能是任何类型,对吗?我的意思是,它只能是一个MyType&&,对吗?从这个意义上说,

我观看了这部电影,从中我学到了关于右值引用、移动和转发的大部分知识。有一次,他说的是右值,而不是变量的类型,他说的是“右值独立于类型”

我知道你可以有这样的方法:

void func(MyType&& rRef)
{
    // Do domething with rRef...
}
这里的
rRef
是一个左值,因为它可以被识别,它的地址可以被获取,等等,即使它的类型是
MyType&

但是右值不能是任何类型,对吗?我的意思是,它只能是一个
MyType&&
,对吗?从这个意义上说,我认为类型并不完全独立于价值。也许我错过了什么

更新:我的观点可以这样说得更清楚。如果在
func()

void gunc(MyType&& rRef)
{
   // ...
}

void gunc(MyType& lRef)
{
   // ...
}

i、 e.通过调用
gunc(std::move(rRef))
gunc(rRef)
,括号之间的结果表达式的类型似乎与右值无关。

我认为您省略了他的部分引用:

最后一点值得记住:左值还是右值 表达式的类型与它的类型无关

他解释道。他的主要观点是:

表达式的类型不会告诉您它是左值还是左值 右旋值

在他的结束语中:

在类型声明中,&&“表示右值引用或 通用引用–可解析为左值或左值的引用 引用或右值引用。普遍引用总是具有相同的含义 对于某些导出的类型T,形式T&&

引用崩溃是导致泛化的机制 引用(在某些情况下实际上只是右值引用) 引用崩溃发生的位置)有时解析为左值 引用,有时是右值引用。它发生在特定的时间 编译过程中可能出现引用的上下文。 这些上下文是模板类型推断、自动类型推断、, typedef的形成和使用,以及decltype表达式


这里使用类型
T
表示任何类型。它可以是
int&
,或者
double&
,或者
Widget&&
——这没关系。

首先,让我们将讨论限制在纯右值引用,而将通用引用放在一边。我们不是在谈论
模板。。。T&&var…

就常规
Type&&var=somevalue右值引用的情况下,我认为其含义如下:

绑定到此引用的内容在绑定到该引用时是“一次性的”。它超出了范围。如果你在装订时修改了它,没有人会知道。在它被绑定时,没有其他引用

这允许我们对右值引用有一些自由,而对其他类型的变量则没有这种自由。想到的第一个用法是使用swap()窃取其内容。

表达式的类型没有任何引用的痕迹。因此,如果我们假设引用可以具有引用类型,那么我们将具有以下内容

int a = 0;
int &ra = a;

int c = a + 42;
int d = ra + 42;
在上面,表达式
a
将具有类型
int
,表达式
ra
将具有类型
int&
。我认为,在规范中几乎所有与表达式和类型相关的规则中,例如说“表达式E必须是X类型”的规则,我们必须添加“…或对X类型的引用”(想想cast操作符)。因此,我有根据地猜测,这将是一个太大的负担,没有用处


C++具有以下类型

  • 表达式的静态类型
仅称为“表达式类型”(若未另外指定动态表达式的含义)。这是表达式的一个属性,指定在编译时从表达式引用的内容中抽象出来的表达式类型。例如,如果
a
引用
int&
int
变量,或者是一个文本
0
,则所有这些表达式都具有类型
int

  • 左值表达式的动态类型
这是左值表达式引用的非基类对象的类型

ofstream fs("/log");
ostream &os = fs;
其中,
os
具有流的静态类型
ostream
和动态类型

  • 对象或引用的类型
这是对象或引用实际具有的类型。一个对象总是有一个单一的类型,并且它的类型永远不会改变。但是什么对象存在于什么位置,只有在运行时才知道,所以一般来说,“对象类型”也是运行时的事情

ostream *os;
if(file)
  os = new ofstream("/log");
else
  os = new ostringstream;
*os
表示的对象类型(以及左值的动态类型
*os
)仅在运行时已知

int *p = new int[rand() % 5 + 1];

这里,由运算符new创建的数组的类型也只在运行时知道,并且(感谢)确实不能逃到静态C++类型系统。臭名昭著的别名规则(粗略地说,它禁止从不兼容的左值读取对象)提到了对象的“动态类型”,大概是因为它想强调运行时关注点的重要性。但严格地说,说对象的“动态类型”很奇怪,因为对象没有“静态类型”

  • 变量或成员的声明类型
这是您在声明中提供的类型。相对于对象的类型或表达式的类型,这有时可能会有细微的不同

struct A {
  A() { }
  int a;
};

const A *a = new const A;
volatile const A *va = a;
这里,表达式
a->a
具有类型
const int
,但是
a->a
解析为的成员的声明类型具有类型
int
(成员实体)。由
a->a
表示的对象类型具有类型
const int
,因为我们创建了
const a
对象
int &&x = 0;
int y = std::move(x);
int z = x;
enum A { X };
template<int Y> struct B { };