什么标准条款要求进行左值到右值的转换?

发布于 2024-11-15 19:35:37 字数 245 浏览 4 评论 0原文

鉴于:

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

有人可以告诉我标准的哪个条款(首选 2003)要求将表达式 xlvalue 转换为 rvalue对象y的初始化?

(或者,如果我错了并且没有发生这样的转换,那么我也想了解这一点!)

Given:

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

Could someone please tell me which clause of the standard (2003 preferred) mandates the conversion of the expression x from lvalue to rvalue in the initialisation of the object y?

(Or, if I'm mistaken and no such conversion takes place, then I'd like to learn that too!)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

独自唱情﹋歌 2024-11-22 19:35:37

我发现将左值视为真实对象并将右值视为存储在对象中的值更容易(如果可能不是 100% 精确)。表达式 x 是一个左值表达式,它引用第一行中定义的对象 x ,但当用作对类型的赋值的右侧时,该类型不是用户定义的类型会读取实际,这就是执行从左值到右值的转换的地方:读取对象的内容。

至于标准中规定转换的特定条款......好吧,我能想到的最接近的是 4.1 [conv.lvalue]/2 (左值到右值转换):

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

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

int x = 5;

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

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

那里的意味着示例中的左值表达式是读取(即转换为右值)。无论如何,前面提到赋值的段落可以应用在这里:如果初始化需要左值而不是右值,则表达式int i = 0;< /code> 格式不正确。

I find it easier (if maybe not 100% precise) to think of lvalue-s as real objects and rvalue-s as the value stored in the object. The expression x is an lvalue expression that refers to the object x defined in the first line, but when used as the right hand side of an assignment to a type that is not a user defined type the actual value is read, and that is where the conversion from lvalue to rvalue is performed: reading the contents of the object.

As to the specific clause in the standard that dictates that conversion... well, the closest that I can think is 4.1 [conv.lvalue]/2 (Lvalue to Rvalue conversion):

The value contained in the object indicated by the lvalue is the rvalue result.

The requirement that the right hand side of the assignment is an rvalue is either implicit or missing from 5.17 [expr.ass], but that is the case or else the following expression would be an error since the rhs is an rvalue and there is no rvalue-to-lvalue conversion:

int x = 5;

EDIT: For initialization, 8.5 [dcl.init]/14, last bullet (which refers to fundamental types) states (emphasis mine):

  • Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. [...]

That value there means that the lvalue expression in your example is read (i.e. converted to an rvalue). At any rate the previous paragraph that referred to assignment could be applied here: if initialization required an lvalue rather than an rvalue, the expression int i = 0; would be ill-formed.

幸福不弃 2024-11-22 19:35:37

确实相信这在某种程度上是直观的(其他人已经说过 - 需要,因此显然需要将对象指示符转换为包含的值其中)。我能想到的最好的办法,4p3:

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

请注意末尾的“当且仅当” - 其初始化器用作右值 >,因为初始化将其用作右值(转换的结果)。所以到 3.10p7

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


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

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

另请注意下面的评论。

I do believe that this is intuitive to some degree (what others already said - the value is needed, so there is an obvious need to convert the object designator to the value contained therein). The best I could come up with, by 4p3:

An expression e can be implicitly converted to a type T if and only if the declaration "T t=e;" is well-formed, for some invented temporary variable t (8.5). The effect of the implicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is a reference type (8.3.2), and an rvalue otherwise. The expression e is used as an lvalue if and only if the initialization uses it as an lvalue.

Note the "if and only if" at the end - the initializer therefor is used as an rvalue, because the initialization uses it as an rvalue (result of the conversion). So by 3.10p7

Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue; see 4.1, 4.2, and 4.3.


EDIT: The paragraph for entering 4p3 can be found at 8.5p16, last bullet:

Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression.

Also note the comments below.

不必了 2024-11-22 19:35:37

这是您要找的吗:

§3.10/7

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

我认为当您编写 int y = x 时,它基本上复制了对象 x 中包含的,这是一个左值,但是 < em>value 本身是一个右值,因此上下文需要一个右值。

§4.1/2 说,

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

也许这两句话可以解答你的疑惑。如果我的理解有误,请指正。我想学习东西。


@Tomalak 的评论:

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

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

Is this what you're looking for:

§3.10/7

Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue; see 4.1, 4.2, and 4.3.

And I think when you write int y = x, it basically copies the value contained in the object x which is a lvalue, but the value itself is an rvalue, hence the context expects an rvalue.

§4.1/2 says,

The value contained in the object indicated by the lvalue is the rvalue result.

Maybe these two quotations clarify your doubt. Correct me if my understanding is wrong. I would like to learn new things.


@Tomalak's comment:

My problem with this is that int& y = x; is valid, so in this case of course x may not be an rvalue. I don't know how irrelevant the difference in my example makes that, though

Well int &y = x does NOT copy the value. It just creates an alias of the object itself. But as I previously said int y = x, basically copies the value which is an rvalue. Hence, the context expects an rvalue, as a copying is being done here.

泪之魂 2024-11-22 19:35:37

初始化程序具有以下语法:

initializer:
        = initializer-clause
        ( expression-list )

initializer-clause:
    assignment-expression
    { initializer-list ,opt }
    { }

在您的示例中,x 是一个赋值表达式,它遵循此语法产生式链:

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“主要表达式”)。

因此,在您的示例中,= 右侧的表达式恰好是左值 的表达式。当然,它可以是右值,但并非必须如此。并且没有强制的左值到右值的转换。

不过,我不确定知道这一点有什么价值。

The initializer has the follwing grammar:

initializer:
        = initializer-clause
        ( expression-list )

initializer-clause:
    assignment-expression
    { initializer-list ,opt }
    { }

In your example, x is an assignment-expression which follows this chain of grammar productions:

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

And an identifier "is an lvalue if the entity is a function or variable" (5.1/4 "Primary expressions").

So in your example, the expression to the right of the = is an expression that happens to be an lvalue. It could be an rvalue of course, but it doesn't have to be. And there is no mandated lvalue-to-rvalue conversion.

I'm not sure what the value in knowing this is, though.

坠似风落 2024-11-22 19:35:37

3.10 左值和右值

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

2 左值指的是一个对象或
功能。一些右值
表达式——类或类的表达式
cvqualified 类类型 — 另请参阅
对象.47)

3 [注意:一些内置运算符和
函数调用产生左值。
[示例:如果 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中的temporary表示
左值和右值的行为
其他重要背景。

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

10 对象的左值是
为了修改所必需的
对象,除了类的右值
type 也可以用来修改它的
特定情况下的参考。
[示例:调用的成员函数
对象(9.3)可以修改该对象。
]

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

12 指向不完整类型的指针可以
可以修改。在某个时刻
当指向的类型为
完成,该对象
指针点也可以修改。

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

14 如果可以使用表达式
修改它引用的对象,
该表达式称为可修改的。一个
试图修改一个程序
通过不可修改的左值对象
或右值表达式格式错误。

15 如果程序尝试访问
通过一个对象存储的值
其中之一以外的左值
以下类型的行为是
undefined48): — 的动态类型
对象,——cv 限定版本
对象的动态类型,-a
有符号或无符号的类型
动态类型对应的类型
对象的类型,是
对应的有符号或无符号类型
到 cv 合格版本
对象的动态类型, — an
聚合或联合类型包括
上述类型之一
其成员(递归地包括
子集合或包含的成员
union), — 一种类型(可能是
cvqualified) 的基类类型
对象的动态类型, — 一个 char
或无符号字符类型。

3.10 Lvalues and rvalues

1 Every expression is either an lvalue
or an rvalue.

2 An lvalue refers to an object or
function. Some rvalue
expressions—those of class or
cvqualified class type—also refer to
objects.47)

3 [Note: some builtin operators and
function calls yield lvalues.
[Example: if E is an expression of
pointer type, then *E is an lvalue
expression referring to the object or
function to which E points. As another
example, the function int& f(); yields
an lvalue, so the call f() is an
lvalue expression. ]

  1. [Note: some builin operators expect lvalue operands. [Example: builtin
    assignment operators all expect their
    left hand operands to be lvalues. ]
    Other builtin operators yield rvalues,
    and some expect them. [Example: the
    unary and binary + operators expect
    rvalue arguments and yield rvalue
    results. ] The discussion of each
    builtin operator in clause 5 indicates
    whether it expects lvalue operands and
    whether it yieldsan lvalue. ]

5 The result of calling a function
that does not return a reference is an
rvalue. User defined operators are
functions, and whether such operators
expect or yield lvalues is determined
by their parameter and return types.

6 An expression which holds a
temporary object resulting from a cast
to a nonreference type is an rvalue
(this includes the explicit creation
of an object using functional notation
(5.2.3)).

7 Whenever an lvalue appears in a context where an rvalue is expected,
the lvalue is converted to an rvalue;
see 4.1, 4.2, and 4.3.

8 The discussion of reference
initialization in 8.5.3 and of
temporaries in 12.2 indicates the
behavior of lvalues and rvalues in
other significant contexts.

9 Class rvalues can have cvqualified
types; nonclass rvalues always have
cvunqualified types. Rvalues shall
always have complete types or the void
type; in addition to these types,
lvalues can also have incomplete
types.

10 An lvalue for an object is
necessary in order to modify the
object except that an rvalue of class
type can also be used to modify its
referent under certain circumstances.
[Example: a member function called for
an object (9.3) can modify the object.
]

11 Functions cannot be modified, but
pointers to functions can be
modifiable.

12 A pointer to an incomplete type can
be modifiable. At some point in the
program when the pointed to type is
complete, the object at which the
pointer points can also be modified.

13 The referent of a constqualified
expression shall not be modified
(through that expression), except that
if it is of class type and has a
mutable component, that component can
be modified (7.1.5.1).

14 If an expression can be used to
modify the object to which it refers,
the expression is called modifiable. A
program that attempts to modify an
object through a nonmodifiable lvalue
or rvalue expression is illformed.

15 If a program attempts to access the
stored value of an object through an
lvalue of other than one of the
following types the behavior is
undefined48): — the dynamic type of
the object, — a cvqualified version of
the dynamic type of the object, — a
type that is the signed or unsigned
type corresponding to the dynamic type
of the object, — a type that is the
signed or unsigned type corresponding
to a cvqualified version of the
dynamic type of the object, — an
aggregate or union type that includes
one of the aforementioned types among
its members (including, recursively, a
member of a subaggregate or contained
union), — a type that is a (possibly
cvqualified) base class type of the
dynamic type of the object, — a char
or unsigned char type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文