未指定时,C++ 运算符的操作数的值类别是啥?

Posted

技术标签:

【中文标题】未指定时,C++ 运算符的操作数的值类别是啥?【英文标题】:What is the value category of the operands of C++ operators when unspecified?未指定时,C++ 运算符的操作数的值类别是什么? 【发布时间】:2013-02-06 03:00:25 【问题描述】:

前提:

C++11 标准将表达式分为三个不相交的值类别lvaluesxvaluesprvalues(第 3.10/1 节)。例如,here 提供了对哪些值类别的说明。

我正在努力弄清楚不同运算符对其操作数的值类别的要求是什么。第 3.10/1 段规定:

[...] 每个表达式都属于该分类法中的基本分类之一:左值、xvalue 或 prvalue。表达式的这个属性称为它的值类别。 [ 注意:第 5 条中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别。例如,内置赋值运算符期望左操作数是左值,右操作数是纯右值并产生左值作为结果。用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定。 ——尾注]

尽管上面的注释声称,第 5 条并不总是很清楚运算符操作数的值类别。例如,这就是关于 assignment 运算符的操作数的值类别的所有内容(第 5.17/1 段):

赋值运算符 (=) 和复合赋值运算符都从右到左分组。 都需要一个可修改的左值作为其左操作数,并返回一个引用左操作数的左值。如果左操作数是位域,则所有情况下的结果都是位域。在所有情况下,赋值都在左右操作数的值计算之后和赋值表达式的值计算之前进行排序。对于不确定顺序的函数调用,复合赋值的操作是单次求值。 [注意:因此,函数调用不应干预左值到右值的转换以及与任何单个复合赋值运算符相关的副作用。 ——尾注]

正确的操作数怎么样?

“rvalue”和“lvalue”这两个词在整个 5.17 节中不再出现。虽然第 3.10/1 段中的注释明确指出内置赋值运算符期望纯右值作为右操作数,但在第 5.17 节中并未明确提及。即使是 5.17/1 的最后一个注释,它提到了左值到右值的转换,似乎也暗示了右值是预期的(否则需要什么转换?),但注释毕竟是非规范的。

关于其他运算符的部分,包括乘法和加法运算符,通常对其操作数的值类别保持沉默。我在标准中找不到任何“默认语句”指出,如果未另行指定,内置运算符的操作数是右值。因此,问题。

问题:

    赋值运算符右操作数的值类别是什么;而且,更一般地说 不指定时如何判断运算符操作数的值类别?是否不受约束(意味着接受任何值类别)?如果是这样,为什么左值到右值的转换应该应用于赋值表达式?

高度赞赏对 C++11 标准的引用。

【问题讨论】:

右侧的值类别是函数参数所期望的(我认为&& 是纯右值,& 是左值,const& 是任何东西,值是任何东西)。对于所有原始类型,我们可以推断签名是T& operator=(const T&rhs),但我认为它没有在任何地方明确说明。 嘿,注释说“第 5 条表示”而不是“第 5 条定义”:) 赋值指示是 5.17p2 “在简单赋值 (=) 中,表达式的值替换了由左操作数引用的对象。" @JohannesSchaub-litb:你知道预期的规范是什么吗?如果定义不明确,我们是否打算假设内置运算符的右操作数在未指定时是右值? @MooingDuck:为什么会这样?对于原始类型,我相信它同样可以是T& operator=(T)。没有? @AndyProwl 不幸的是,我认为没有什么可以说的。我认为规范没有明确规定,并遗漏了承诺的“每个内置运算符的讨论”:) 【参考方案1】:

是的,它指定不正确,has been covered before。基本上,每次需要左值表达式时都会枚举,因此我们假设每个其他操作数都必须是纯右值表达式。

所以回答你的问题:

    prvalue。 如果未指定,则为prvalue。

链接答案中引用的注释似乎已经更改了几次。 C++11 标准第 3.10 节的引用如下(目前在最新草案中是相同的):

[ 注意:第 5 章中对每个内置运算符的讨论表明了它产生的值的类别以及它所期望的操作数的值类别。例如,内置赋值运算符期望左操作数是左值,右操作数是纯右值并产生左值作为结果。用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定。 ——尾注]

这里甚至明确表示赋值运算符期望正确的操作数是纯右值。当然,这是一个注释,因此是非规范性的。

【讨论】:

我在我的标准草案中找不到您链接的答案据称是 3.10 一部分的措辞。 n3485 草案有什么不同吗?我没有原来的标准。例如“[示例:一元和二元 + 运算符期望右值参数并产生右值结果。-结束示例]”缺失。此外,如果未指定,为什么我们可以“假设每个其他操作数都必须是纯右值表达式”? @AndyProwl 我同意我们必须假设一些未指定的东西是愚蠢的,但不幸的是它的定义不是很好。这是编译器开发人员基本上同意的事情。从逻辑上讲,如果操作需要使用该操作数的值,则该操作数是纯右值。我目前正在调查是否有问题报告。 谢谢,您的回答基本上证实了我的怀疑,尽管我希望这只是我的疏忽。 +1,如果没有更令人信服的答案,将在几个小时内接受。 @AndyProwl 我快速搜索了问题列表,但没有找到任何东西,很遗憾。 如果有任何规范性语言支持它,这个答案就很棒。不幸的是,注释本身并不是语言定义的一部分。你知道是否有任何规范语言支持任何未指定的操作数具有纯右值类别的(非常合理的)猜想?

以上是关于未指定时,C++ 运算符的操作数的值类别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

c语言中规定 赋值运算符的左边必须是啥?

java中用new运算符新申请建立一个对象的时候返回值是啥?

C++ 的箭头 (->) 运算符的正式名称是啥?

js中<<是啥运算符

c语言中以rw1_2.c保存是啥意思

C++ | 运算符重载