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

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

假设我们有以下声明:

int x;


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

编写这样的新语法:

int&& ref


代替

int& ref


使人们认为我们已经完成了与类型相关的操作,但实际上我们已经完成了与表达式相关的操作,而不是类型。 (我们指定了可以将表达式绑定到这些变量。)

可以通过另一种方式来区分“临时”和“非临时”,也许是这样的:

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


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

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

最佳答案

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

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

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

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

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

或者,您可以创建一个新类型并免费获取其中的大多数。您仍然需要研究这种新类型的重载解析的工作方式,并且仍然必须定义右值引用绑定规则,但是函数签名的概念没有改变,并且不需要多余的额外信息渠道一种。

为此目的使用引用还允许引用折叠规则,这些规则是“完美”转发的基础:编写单个(模板)函数的能力,该函数可以将任何值类别的表达式转发到目标保留目的地是否可以从中复制/移动的完整信息。

关于c++ - 右值引用不会将类型和类别混合在一起吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56306144/

10-11 22:13
查看更多