什么样的标准子句要求进行左值到右值的转换

What standard clause mandates this lvalue-to-rvalue conversion?

本文关键字:转换 标准 子句 什么样      更新时间:2023-10-16

给定:

int main() {
   int x = 0;
   int y = x; // <---
}

有人能告诉我标准的哪一条(2003年首选)要求在对象y的初始化中将表达式x左值转换为右值

(或者,如果我错了,没有发生这样的转换,那么我也想学习一下!)

我发现把lvalue看作真实对象,把rvalue看作存储在对象中的值更容易(如果可能不是100%精确的话)。表达式x是指第一行中定义的对象x的左值表达式,但当用作非用户定义类型的类型赋值的右手边时,会读取实际,也就是执行从左值到右值转换的地方:读取对象的内容。

至于标准中规定转换的具体条款。。。嗯,我能想到的最接近的是4.1[conv.value]/2(lvalue到Rvalue的转换):

由左值指示的对象中包含的值是右值结果。

赋值的右侧是右值的要求在5.17[expr.ass]中是隐含的或缺失的,但事实就是这样,否则以下表达式将是错误的,因为rhs是右值,并且没有右值到左值的转换:

int x = 5;

编辑:对于初始化,8.5[dcl.init]/14,最后一个项目符号(指基本类型)状态(强调矿):

  • 否则,正在初始化的对象的初始值是初始值设定项表达式的(可能已转换)。[…]

意味着示例中的左值表达式为read(即转换为右值)。无论如何,前面提到赋值的段落可以应用于此:如果初始化需要左值而不是右值

Ido认为这在某种程度上是直观的(正如其他人已经说过的那样,需要,因此显然需要将对象指示符转换为其中包含的值)。我能想出的最好的办法,4点3分:

表达式e可以隐式转换为类型T,当且仅当声明"T T=e;"格式良好时,对于某些发明的临时变量T(8.5)。隐式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同如果T是引用类型(8.3.2),则结果为左值,否则为右值。表达式e被用作左值,当且仅当初始化将其用作左值时

注意末尾的"if and only if"-其初始值设定项被用作右值,因为初始化将其用作右值(转换的结果)。所以到3.10p7

每当左值出现在期望右值的上下文中时,左值就会转换为右值;参见4.1、4.2和4.3。


编辑:输入4p3的段落可以在8.5p16找到,最后一个项目符号:

否则,正在初始化的对象的初始值是初始值设定项表达式的值(可能已转换)。

还要注意下面的评论。

这就是您想要的:

§3.10/7

每当左值出现在期望右值的上下文中时,左值就会转换为右值;参见4.1、4.2和4.3。

我认为当你写int y = x时,它基本上复制了对象x中包含的,这是一个左值,但的值

§4.1/2说,

由左值指示的对象中包含的值是右值结果。

也许这两句话澄清了你的疑虑。如果我的理解有误,请纠正我。我想学习新的东西。


@托马拉克评论:

我的问题是int&y=x;是有效的,所以在这种情况下,x当然可能不是右值。我不知道我的例子中的差异有多无关紧要,尽管

int &y = x不复制该值。它只是创建对象本身的一个别名。但正如我之前所说的int y = x,基本上复制,这是一个右值。因此,上下文需要一个右值,因为这里正在进行复制。

初始值设定项具有以下语法:

initializer:
        = initializer-clause
        ( expression-list )
initializer-clause:
    assignment-expression
    { initializer-list ,opt }
    { }

在您的示例中,x是遵循以下语法生成链的assignment-expression

conditional-expression  ==>
    logical-or-expression ==>
        logical-and-expression  ==>
            inclusive-or-expression  ==>
                exclusive-or-expression  ==>
                    and-expression  ==>
                        equality-expression  ==>
                            relational-expression  ==>
                                shift-expression  ==>
                                    additive-expression  ==>
                                        multiplicative-expression  ==>
                                            pm-expression  ==>
                                                cast-expression  ==>
                                                    unary-expression  ==>
                                                        postfix-expression  ==>
                                                            primary-expression  ==> 
                                                                id-expression  ==>
                                                                    unqualified-id  ==>
                                                                        identifier

标识符"如果实体是函数或变量,则为左值"(5.1/4"主表达式")。

所以在您的例子中,=右边的表达式恰好是lvalue。当然,它可以是rvalue,但不一定必须是。并且没有强制的左值到右值转换。

不过,我不确定知道这件事有什么价值。

3.10价值和价值

1每个表达式都是左值或右值。

2左值是指对象或作用一些价值表达式——类或cvqualified类类型--也可参考对象。47)

3[注:一些内置运算符和函数调用产生lvalues。[示例:如果E是指针类型,则*E为左值引用对象的表达式或E指向的函数。作为另一个例如,函数int&f();收益率一个左值,所以调用f()是左值表达式。]

  1. [注意:一些内置运算符需要左值操作数。[示例:内置赋值运算符都期望左手操作数为左值。]其他内置运算符产生右值,有些人期待他们。[示例:应为一元和二进制+运算符右值自变量与产生右值结果。]每个人的讨论子句5中的内置运算符表示是否期望左值操作数和它是否有价值。]

5调用函数的结果不返回引用的是右值。用户定义的运算符是功能,以及此类操作员是否期望值或收益值已确定通过它们的参数和返回类型。

6包含由强制转换产生的临时对象到非引用类型是一个右值(这包括显式创建使用函数表示法的对象(5.2.3)).

7每当左值出现在期望右值的上下文中时,将左值转换为右值;请参见4.1、4.2和4.3。

8参考文献的讨论8.5.3中的初始化和12.2中的临时费用表示中的左值和右值的行为其他重要上下文。

9类值可以具有cvqualified类型;非类右值总是cv不合格类型。R值应总是有完整的类型或void类型除了这些类型之外,lvalues也可以有不完全类型。

10对象的左值是为了修改对象,除了类的右值类型也可以用于修改其在某些情况下指代。[示例:调用的成员函数对象(9.3)可以修改该对象。]

11功能不能修改,但是指向函数的指针可以是可修改。

12指向不完整类型的指针可以可修改。在当指向的类型为complete指针点也可以被修改。

13 constqualified的指代表达式不应修改(通过该表达式),除了如果它是类类型并且具有可变组件,该组件可以修改(7.1.5.1)。

14如果一个表达式可以用于修改它所指的对象,该表达式称为可修改表达式。A.试图修改对象通过不可修改的左值或者右值表达式不正确。

15如果程序试图访问通过的左值行为是以下类型undefined48):--的动态类型对象,--的cvqualified版本对象的动态类型,-a有符号或无符号的类型与动态类型对应的类型对象的类型有符号或无符号类型对应的cvqualified版本对象的动态类型,--包含的聚合或并集类型上述类型之一其成员(递归地包括亚集体的成员并集),--一种类型cvqualified)的基类类型对象的动态类型,--一个字符或无符号字符类型。