右值引用不会将类型和类别混合在一起吗?
Doesn't rvalue reference mix together type and category?
这post反映了我目前对价值类别的理解水平。
值类别是一个 属性 表达式。
类型是变量的属性。
假设我们有以下声明:
int x;
x 是什么?它是一个变量,它是一个表达式。
写一个像这样的新语法:
int&& ref
而不是
int& ref
让人以为我们做了类型相关的东西,其实我们做的是表达式相关的东西,而不是类型。 (我们已经指定了哪些表达式可以绑定到这些变量。)
可能区分 "temporaries" 和 "non-temporaries" 可以用另一种方式来完成,也许是这样的:
void func(int&); // for "non-temporaries"
void func((int&)); // for "temporaries
或其他方式,但不要摆弄类型。
所以我的问题是:
是否有必要将有关表达式类别的信息编码为类型的语法?做出此设计决定的原因是什么?
右值引用是与左值引用不同的类型,因此它们可以对某些内容进行编码:用户在创建该引用时的特定意图。如果您进行右值引用,则您特别希望可以从中移动它引用的对象。这是与使用左值引用不同的意图。
仅使用名称无法检测到该特定意图;右值引用变量的值类别是左值。但这种意图可以从 type 中检测到。类型很重要。
我们希望能够在这个声明的意图上重载函数,有一个重载可以接受一个可以移动的对象,另一个不能。这是区分复制构造函数和移动构造函数的基础。 C++ 基于类型重载函数,所以...我们必须在类型级别指定此意图。
在您的 func
示例中,如果 int&
和 (int&)
是同一类型,那么根据 C++ 当前存在的规则,这两个 func
函数声明 相同的函数。因此,您需要发明新规则,将 "function signature" 的概念定义为不仅仅是所涉及的类型。您必须弄乱重载决策以确定调用哪个函数。等等
另外,std::move
有效(即 return 值可以绑定到右值引用)因为右值引用类型的 return 值的值类别定义为一个 xvalue。并且 xvalues 可以绑定到右值引用。按照您的方式,此 (&)
语法必须具有类似的属性。但它不能基于类型,因为根据定义,它不会改变类型。所以本质上,你必须声明引用类型可以有这个额外的,non-type 信息位于类型旁边。此信息无法通过任何普通接口查询,不像表达式的类型信息可以通过 decltype
.
查询
或者您可以创建一个新类型并免费获得其中的大部分内容。您仍然需要研究重载解析如何为这种新类型工作,您仍然需要定义右值引用绑定规则,但函数签名的概念没有改变,您不需要旁边这个笨拙的额外信息通道一种。
为此目的使用引用还允许 reference-collapsing 规则,这些规则是 "perfect" 转发的基础:编写单个(模板)函数转发任何表达式的能力值类别以一种保持目的地不变的方式到达目的地是否可以 copy/move 来自他们。
这post反映了我目前对价值类别的理解水平。
值类别是一个 属性 表达式。 类型是变量的属性。
假设我们有以下声明:
int x;
x 是什么?它是一个变量,它是一个表达式。
写一个像这样的新语法:
int&& ref
而不是
int& ref
让人以为我们做了类型相关的东西,其实我们做的是表达式相关的东西,而不是类型。 (我们已经指定了哪些表达式可以绑定到这些变量。)
可能区分 "temporaries" 和 "non-temporaries" 可以用另一种方式来完成,也许是这样的:
void func(int&); // for "non-temporaries"
void func((int&)); // for "temporaries
或其他方式,但不要摆弄类型。
所以我的问题是: 是否有必要将有关表达式类别的信息编码为类型的语法?做出此设计决定的原因是什么?
右值引用是与左值引用不同的类型,因此它们可以对某些内容进行编码:用户在创建该引用时的特定意图。如果您进行右值引用,则您特别希望可以从中移动它引用的对象。这是与使用左值引用不同的意图。
仅使用名称无法检测到该特定意图;右值引用变量的值类别是左值。但这种意图可以从 type 中检测到。类型很重要。
我们希望能够在这个声明的意图上重载函数,有一个重载可以接受一个可以移动的对象,另一个不能。这是区分复制构造函数和移动构造函数的基础。 C++ 基于类型重载函数,所以...我们必须在类型级别指定此意图。
在您的 func
示例中,如果 int&
和 (int&)
是同一类型,那么根据 C++ 当前存在的规则,这两个 func
函数声明 相同的函数。因此,您需要发明新规则,将 "function signature" 的概念定义为不仅仅是所涉及的类型。您必须弄乱重载决策以确定调用哪个函数。等等
另外,std::move
有效(即 return 值可以绑定到右值引用)因为右值引用类型的 return 值的值类别定义为一个 xvalue。并且 xvalues 可以绑定到右值引用。按照您的方式,此 (&)
语法必须具有类似的属性。但它不能基于类型,因为根据定义,它不会改变类型。所以本质上,你必须声明引用类型可以有这个额外的,non-type 信息位于类型旁边。此信息无法通过任何普通接口查询,不像表达式的类型信息可以通过 decltype
.
或者您可以创建一个新类型并免费获得其中的大部分内容。您仍然需要研究重载解析如何为这种新类型工作,您仍然需要定义右值引用绑定规则,但函数签名的概念没有改变,您不需要旁边这个笨拙的额外信息通道一种。
为此目的使用引用还允许 reference-collapsing 规则,这些规则是 "perfect" 转发的基础:编写单个(模板)函数转发任何表达式的能力值类别以一种保持目的地不变的方式到达目的地是否可以 copy/move 来自他们。