c++ - Clarifying the value categories of expressions
问题描述
In 2010, Bjarne Stroustrup, the creator of C++, wrote the paper “New” Value Terminology in which he explains the value categories of expressions introduced in the C++11 standard* (lvalue, xvalue, and prvalue, and their generalizations glvalue and rvalue):
There were only two independent properties:
- “has identity” – i.e. and address, a pointer, the user can determine whether two copies are identical, etc.
- “can be moved from” – i.e. we are allowed to leave to source of a “copy” in some indeterminate, but valid state
This led me to the conclusion that there are exactly three kinds of values (using the regex notational trick of using a capital letter to indicate a negative – I was in a hurry):
- iM: has identity and cannot be moved from
- im: has identity and can be moved from (e.g. the result of casting an lvalue to a rvalue reference)
- Im: does not have identity and can be moved from
The fourth possibility (“IM”: doesn’t have identity and cannot be moved) is not useful in C++ (or, I think) in any other language. In addition to these three fundamental classifications of values, we have two obvious generalizations that correspond to the two independent properties:
- i: has identity
- m: can be moved from
In 2015, Richard Smith, then the C++ standard editor, wrote the paper Guaranteed copy elision through simplified value categories in which he explains the rewording of the value categories of expressions introduced in the C++17 standard**:
However, these rules are hard to internalize and confusing -- for instance, an expression that creates a temporary object designates an object, so why is it not an lvalue? Why is
NonMoveable().arr
an xvalue rather than a prvalue? This paper suggests a rewording of these rules to clarify their intent. In particular, we suggest the following definitions for glvalue and prvalue:
- A glvalue is an expression whose evaluation computes the location of an object, bit-field, or function.
- A prvalue is an expression whose evaluation initializes an object, bit-field, or operand of an operator, as specified by the context in which it appears.
That is: prvalues perform initialization, glvalues produce locations.
Denotationally, we have:
- glvalue :: Environment -> (Environment, Location)
- prvalue :: (Environment, Location) -> Environment
So far, this is not a functional change to C++; it does not change the classification of any existing expression. However, it makes it simpler to reason about why expressions are classified as they are:
struct X { int n; }; extern X x; X{4}; // prvalue: represents initialization of an X object x.n; // glvalue: represents the location of x's member n X{4}.n; // glvalue: represents the location of X{4}'s member n; // in particular, xvalue, as member is expiring
Basically, Smith only reworded Stroustrup’s definition of a prvalue from ‘does not have identity’ to ‘performs initialization’.
I am still unclear about the following things (so these are my questions):
- The meaning of Smith’s notations ‘glvalue :: Environment -> (Environment, Location)’ and ‘prvalue :: (Environment, Location) -> Environment’.
- The rationale for which Smith’s expression
X{4}.n
is not a prvalue under the C++17 standard**, since it performs initialization of the complete objectX{4}
(called ‘temporary object materialization’) and in particular of its subobjectn
. - The rationale for which Smith’s expression
X{4}.n
is not a prvalue under the C++11 standard*, since it represents a subobject of a temporary object.
Notes
* The value categories of expressions in the C++11 standard, [basic.lval/1] (bold emphasis mine):
- An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then
*E
is an lvalue expression referring to the object or function to whichE
points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. — end example ]- An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references ([dcl.ref]). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. — end example ]
- A glvalue (“generalized” lvalue) is an lvalue or an xvalue.
- An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object ([class.temporary]) or subobject thereof, or a value that is not associated with an object.
- A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as
12
,7.3e5
, ortrue
is also a prvalue. — end example ]
** The value categories of expressions in the C++17 standard, [basic.lval/1] (bold emphasis mine):
- A glvalue is an expression whose evaluation determines the identity of an object, bit-field, or function.
- A prvalue is an expression whose evaluation initializes an object or a bit-field, or computes the value of the operand of an operator, as specified by the context in which it appears.
- An xvalue is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime). [ <em>Example: Certain kinds of expressions involving rvalue references yield xvalues, such as a call to a function whose return type is an rvalue reference or a cast to an rvalue reference type. — <em>end example ]
- An lvalue is a glvalue that is not an xvalue.
- An rvalue is a prvalue or an xvalue.
解决方案
- 这已在评论中得到了很大的回答,但要详细说明:任何命令式系统的语义都可以通过将“世界”的状态(从所有 RAM 开始)作为函数的参数和(部分)它的返回值。这种表示法表明评估一个左值从那个环境中选择一个地址(一个对象的身份)(并且可能改变它),而评估一个纯右值需要这样一个位置并改变环境以包含一个初始化的对象(可能有其他副作用) )。
X{4}.n
不初始化n
(用什么,本身?);它允许访问(即识别)由 just 建立的值X{4}
(它被具体化以便有特定n
的识别)。- 您对它的临时状态是正确的,但这只是使其成为rvalue;prvalue 是一个右值,它也不是一个xvalue。
推荐阅读
- python-3.x - 尽管采购了pythonpath,但由于找不到模块错误而无法运行python文件
- python - Django 2 form is_valid 即使在有效的表单数据上也不起作用
- razor - 我可以在 Blazor 中编写一个在视图中动态呈现元素的函数吗?
- excel - SUMPRODUCT((range={"this";"that"})*(other conditions)) return N/A if some cell of range does not meet this or that
- gradle - Gradle:为传递依赖配置存储库
- sql - 如何从 MSSQL 数据库中检索关系
- cassandra - Datastax CassandraRoleManager 跳过了默认角色设置,一些节点尚未准备好
- java - JavaFX TableView 过滤器不保留选择
- react-native - ReactNative,如何在 ScrollView 中获取位置 FlatList 项
- python - 如何在 one2many 弹出表单中加载另一个表的列表以将其添加到 odoo 12 中的主表单?