重值引用不是将类型和类别混合在一起吗?

Doesn't rvalue reference mix together type and category?

本文关键字:混合 在一起 类型 引用      更新时间:2023-10-16

这篇文章反映了我目前对价值类别的理解水平。

值类别是表达式的属性。 类型是变量的属性。

假设我们有以下声明:

int x;

什么是 x?它是一个变量,它是一个表达式。

编写如下新语法:

int&& ref

而不是

int& ref

让人们认为我们做了一些与类型相关的事情,但实际上我们做了一些与表达式相关的事情,而不是类型。(我们已经指定了哪些表达式可以绑定到这些变量。

可能区分"临时">

和"非临时"可以用另一种方式完成,也许是这样的:

void func(int&); // for "non-temporaries"
void func((int&)); // for "temporaries

或其他方式,但不摆弄类型。

所以我的问题是: 是否有必要将有关表达式类别的信息编码为类型的语法?做出此设计决定的原因是什么?

右值引用是与左值引用不同的类型,因此它们可以对某些内容进行编码:用户创建该引用时的特定意图。如果进行右值引用,则特别希望可以从中移动它引用的对象。这是与使用左值引用不同的意图。

仅使用名称无法检测到该特定意图;右值引用变量的值类别是左值。但是可以从类型中检测到该意图。类型很重要。

我们希望能够在这个声明的意图上重载函数,让一个重载可以接受一个可以移动的对象,而另一个不能。这是区分复制构造函数和移动构造函数的基础。C++基于类型的重载函数,因此...我们必须在类型级别指定此意图。

func示例中,如果int&(int&)是同一类型,则根据当前存在的C++规则,这两个func函数声明相同的函数。因此,您需要发明新的规则,将"函数签名"的概念定义为不仅仅是所涉及的类型。您必须弄乱重载解析才能确定调用哪个函数。等。

另外,std::move工作(即,返回值可以绑定到右值引用),因为右值引用类型的返回值的值类别被定义为 xvalue。xvalues 可以绑定到右值引用。按照您的方式,此(&)语法必须具有类似的属性。但它不能基于类型,因为根据定义,它不会更改类型。因此,从本质上讲,您必须声明引用类型可以在类型旁边包含此额外的非类型信息。此信息不能由任何普通接口查询,这与表达式的类型信息不同,表达式的类型信息可以通过decltype查询。

或者,您可以创建一个新类型并免费获得其中的大部分。您仍然需要研究重载解析如何适用于此新类型,并且仍然必须定义 rvalue 引用绑定规则,但函数签名的概念保持不变,并且您不需要位于类型旁边的这个尴尬的额外信息通道。

为此意图使用引用还允许引用折叠规则,这是"完美"转发的基础:能够编写单个(模板)函数,该函数将任何值类别的表达式转发到目标,以保持目标是否可以复制/移动

的方式。