Temporary initialization and Reference initialization - c++

I am trying to understand how reference initialization. For example, let's look at a typical example.
double val = 4.55;
const int &ref = val;
I can think of 2 possibilities of what is happening in the above snippet.
Possibility 1
The usual explanation is given as follows:
Here a temporary(prvalue) of type int with value 4 is created and then the reference ref is bound to this temporary(prvalue) int object instead of binding to the variable val directly. This happens because the type of the variable val on the right hand side is double while on the left hand side we have a reference to int. But for binding a reference to a variable the types should match. Moreover, the lifetime of the temporary prvalue is extended.
Possibility 2
I think there is another possibility that could happen which is as follows:
Here a temporary(prvalue) of type int with value 4 is created. But since const int &ref expects a glvalue and currently we've a prvalue, the temporary materialization kicks in and so the prvalue is converted to an xvalue. Then the reference ref is bound to this materialized xvalue(since xvalue is also a glvalue) instead of binding to the variable val directly. This happens because the type of the variable val on the right hand side is double while on the left hand side we have a reference to int. But for binding a reference to a variable the types should match. Moreover, the lifetime of the materialized temporary xvalue is extended.
My questions are:
Which of the above explanation is correct according to the C++11 standard. I am open to accept that none of the explanation above is correct in which case what is the correct explanation.
Which of the above explanation is correct according to the C++17 standard. I am open to accept that none of the explanation above is correct in which case what is the correct explanation.
I am also confused to whether a prvalue in the first step of both of the possibilities above, is actually a temporary object? Or the xvalue is the actual object. I mean do we have 2 temporary objects, like the first one due to "conversion to prvalue" and second one due to the "prvalue to xvalue" conversion(temporary materiliazation). Or do we only have one temporary which is due to the "prvalue to xvalue" temporary materialization.
PS: I am not looking for a way to solve this. For example, i know that i can simply write:
const double &ref = val;. My aim is to understand what is happening according to C++11 and C++17 standards.

val in const int &ref = val; is a lvalue, not a prvalue. Even if it is converted to a prvalue, this doesn't mean creation of a temporary in either C++11 or C++17. In C++17 this isn't the case since only prvalue-to-xvalue conversion (and some special cases not relevant here) creates a temporary, while in C++11 [conv.lval]/2 says that only for class types lvalue-to-rvalue conversion creates a temporary.
The initialization of a reference is explained in [dcl.init.ref].
In C++11, all previous cases fall through and so according to [dcl.init.ref]/5.2.2 a temporary of the destination type is created and initialized by copy-initialization from the initializer expression and the reference is bound to that temporary. In this copy-initialization the lvalue val is converted to a prvalue of type double and then to a prvalue of type int, neither of these steps creating additional temporaries.
In C++17, all cases fall through until [dcl.init.ref]/5.2.2, which states that the initializer expression is first implicitly converted to a prvalue of the destination type, which does not imply creation of a temporary, and then the temporary materialization conversion (prvalue-to-xvalue conversion) is applied and the reference bound to the result, i.e. the xvalue referring to the temporary.
In the end there is always exactly one temporary, the one created according to the rule in [dcl.init.ref].

Lets look at each of the cases(C++11 vs C++17) separately.
C++11
From decl.init.ref 5.2.2:
Otherwise, a temporary of type “ cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy-initialization ([dcl.init]). The reference is then bound to the temporary.
One more important thing to note is that from basic.lval#4:
Class prvalues can have cv-qualified types; non-class prvalues always have cv-unqualified types...
When applied to your example, this means that a temporary of type int is created and is initialized from the initializer expression val using the rules for a non-reference copy-initialization. The temporary int so created has the value category of prvalue if/when used as an expression.
Next, the reference ref is then bound to the temporary int created which has value 4. Thus,
double val = 4.55;
const int &ref = val; // ref refers to temporary with value 4
C++17
From decl.init.ref 5.2.2.2:
Otherwise, the initializer expression is implicitly converted to a prvalue of type “cv1 T1”. The temporary materialization conversion is applied and the reference is bound to the result.
When applied to your example, this means that the initializer expression val is implicitly converted to a prvalue of type const int. Now we currently have a prvalue const int. But before temporary materialization is applied, expr 6 kicks in which says:
If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.
This means before temporary materialization could happen, the prvalue const int is adjusted to prvalue int.
Finally, temporary materialization is applied and and ref is bound to the resulting xvalue.

Here's my take for C++17:
double val = 4.55;
const int &ref = val;
We're binding a const int reference to the lvalue expression of type double denoted by val. According to the declaration of references;
Otherwise, the initializer expression is implicitly converted to a prvalue of type “T1”.
we convert the expression val to type int. Note that this implicit type! conversion fits with the draft.
Next,
The temporary materialization conversion is applied, considering the type of the prvalue to be “cv1 T1”, ...
in order to apply the temporary materialization (also known as prvalue -> xvalue conversion), we must have fully matched types so the expression is aditionally converted to const int is considered to be const int without any conversions (source). The value category remains the same (prvalue). And finally,
... and the reference is bound to the result.
we have a reference binding of type T to a prvalue of type T which induces temporary materialization (source) and val gets converted to xvalue. The created temporary object is of type const int and value of 4.
EDIT: And to answer your questions, of course. So neither of the given possibilities aren't technically correct for C++17 right at the start. Strictly speaking, neither prvalues nor xvalues are temporary objects. Rather, they are value category of expressions and expression might (or might not) denote a (temporary) object. So technically, xvalues denote temporary objects while prvalues don't. You could still say that xvalues are temporary objects, that's completely fine by me as long as you know what you're talking about.

Related

How expressions designating temporary objects are xvalue expression?

From cppreference, I am trying to understand expressions that yield xvalues, and I ended up with this summary:
The following expressions are xvalue expressions:
...
any expression that designates a temporary object, after temporary
materialization.
Temporary materialization is:
A prvalue of any complete type T can be converted to an xvalue of the
same type T. This conversion initializes a temporary object of type T
from the prvalue by evaluating the prvalue with the temporary object
as its result object, and produces an xvalue denoting the temporary
object.
And per my understanding from the above quote, temporary materialization involves converting the prvalue into an xvalue to initialize the created temporary; and that's mean that whenever prvalue is materialized, an xvalue expression appears. So I found myself have to understand when exactly a prvalue is materialized. then I have checked this from cppreference:
Temporary materialization occurs in the following situations:
1- when binding a reference to a prvalue;
2- when performing a member access on a class prvalue;
3- when performing an array-to-pointer conversion
or subscripting on an array prvalue;
4- when initializing an object of type std::initializer_list from a braced-init-list;
5- when typeid is applied to a prvalue
6- when sizeof is applied to a prvalue
7- when a prvalue appears as a discarded-value
expression.
Note that temporary materialization does not occur when initializing an object from a prvalue of the same type (by direct-initialization or copy-initialization): such object is initialized directly from the initializer. This ensures "guaranteed copy elision".
Can anyone help me with simple examples how xvalue expression are involved in the situation 3, 4 and 7.
situation 3, 4 and 7.
7 (discarded expression) is the easiest:
42; // materialize and discard
std::string{"abc"}; // materialize and discard
3 (doing things to array rvalue) requires knowing how to make them
using arr_t = int[2][3];
int a = arr_t{}[0][0]; // have to materialize to be able to subscript
4 (making an std::initializer_list) is what it says on the tin
std::initializer_list<std::string>{
"abc"s,
"def"s
}; // have to materialize the two strings
// to place them in the secret array pointed to by the list

How to understand the prvalue within list-initialization of a reference

Consider the following code:
#include <iostream>
struct A {
A() = default;
A(int) {
}
};
int main() {
A const& rf = { 0 };
}
Cite the quote in standard here:
Otherwise, if T is a reference type, a prvalue(#1) of the type referenced by T is generated. The prvalue initializes its result object by copy-list-initialization or direct-list-initialization, depending on the kind of initialization for the reference. The prvalue is then used to direct-initialize the reference. [ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type.  — end note ]
I don't understand the "prvalue" at #1,How to denote this prvalue? And continue, why use the prvalue initialize its reuslt object by list-initialization again,and why not use the reuslt object to direct-initialize the reference instead using the prvalue?
To descript the prvalue concretely,Does A{0} denote the prvalue(at #1)?
So my questions are:
1.How to denote the prvalue (at #1) or what actullay the prvalue is
2.Since a prvalue of type T'(remove reference) has been generated,why not use the prvalue direct-initialize the reference
3.I very confused about "The prvalue initializes its result object" by list-initialization again
what actullay the prvalue is
A prvalue is a kind of expression. In C++17 and beyond, it is specifically a kind of expression that initializes an object. So a prvalue is just a mechanism for initializing an object. As such, the only characteristics of a prvalue are the type of the prvalue (ie: the type of the object it will initialize) and the mechanism that it will use to initialize that object.
How the prvalue gets used determines which object gets initialized by it.
So, what is the prvalue in this instance? It's an initializer that uses a form of list-initialization on some object of the type referenced by T. That is all there is to know about the prvalue.
why not use the prvalue direct-initialize the reference
The prvalue does "direct-initialize" the reference. The spec you quoted says so: "The prvalue is then used to direct-initialize the reference."
If what you're asking is why there is a prvalue between the braced-init-list (aka: {...}) and the reference, it's because, on some level, the code you have written makes no sense.
A reference refers to an object, and thus must be initialized by giving it an object. A braced-init-list is not an object; in fact, it isn't even an expression. It is a grammatical construct used to initialize an object. So you tried to initialize a reference to an object with something that isn't an object. By all rights, this should be a compile error.
However, there is an obvious interpretation as to what your code meant to do. Namely, use the braced-init-list to initialize an object, then use the object to initialize the reference. So that's what C++ does.
I very confused about "The prvalue initializes its result object" by list-initialization again
As previously stated, a prvalue consists of two things: the type of an object to be initialized by the prvalue, and the mechanism to use to initialize it. This sentence explains the latter part.

Cv-qualifications of prvalues (revisited)

This is a followup to my previous question, where the apparent consensus was that the change in treatment of cv-qualifications of prvalues was just a fairly minor and inconsequential change intended to solve some inconsistencies (e.g. functions returning prvalues and declared with cv-qualified return types).
However, I see another place in the standard that appears to rely on prvalues having cv-qualified types: initialization of const references with prvalues through temporary materialization conversion. The relevant wording can be found in multiple spots in 9.3.3/5
[...] If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied [...]
[...] Otherwise, the initializer expression is implicitly converted to a prvalue of type “cv1 T1”. The temporary materialization conversion is applied and the reference is bound to the result.
The intent is obviously to make sure that when we get to the actual temporary materialization conversion
7.3.4 Temporary materialization conversion
1 A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object. [...]
the type T that it receives as input includes the required cv-qualifications.
But how does that cv-qualification survive the 7.2.2/2 in case of non-class non-array prvalue?
7.2.2 Type
2 If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.
Or does it?
E.g. what kind of temporary do we get in this example
const int &r = 42;
Is the temporary const or not? Can we do
const_cast<int &>(r) = 101; // Undefined or not?
without triggering undefined behavior? If I'm not mistaken, the original intent was to obtain a const int temporary in such cases. Is it still true? (For class types the answer is clear - we get a const temporary.)
Why are you doubting the language of 7.2.2? This seems pretty unambiguous that cv qualifiers are discarded on non-class, non-array prvalues, so the type T in temporary materialization is a non-const, non-volatile type.
If that weren't the case, then you wouldn't be able to bind prvalues to non-const rvalue references. Yet it seems overwhelmingly likely that the standard was intended to accept programs such as this:
#include <type_traits>
template<typename T> void
f(T &&t)
{
static_assert(std::is_same_v<decltype(t), int&&>);
++t;
}
int
main()
{
f(5);
}
E.g. what kind of temporary do we get in this example const int &r = 42; Is the temporary const or not?
Let's analyze your example to see whether it's const or not. Given this example
const int &r = 42;
The applicable wording from the standard is [dcl.init.ref]/5
A reference to type “cv1 T1” is initialized by an expression of
type “cv2 T2” as follows:
(5.1) [..]
(5.2) [..]
(5.3) Otherwise, if the initializer expression
(5.3.1) is an rvalue (but not a bit-field) or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or
(5.3.2) [..]
then the value of the initializer expression in the first case and the result of the conversion in the second case is called the converted initializer. If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied. In any case, the reference is bound to the resulting glvalue (or to an appropriate base class subobject).
It's already known that the initializer expression 42 is a prvalue, and const int (cv1 T1) is reference-compatible with int (cv2 T2). And the converted initializer here is of type int (T4); then it's adjusted, via [conv.qual], to const int (cv1 T4); then temporary materialization ([conv.rval]) gets applied. Note that, [expr.type]/2 doesn't apply here because the initial type of the prvalue is cv-unqualified type:
If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.
Note also, it cannot be applied after adjustment to cv1 T4 because cv1 T4 is not the initial type of the prvalue.
So the adjusted prvalue has type const int (cv1 T4) Then, temporary materialization gets applied to this prvalue; [conv.rval]:
A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T [..]
The const int prvalue gets converted to an xvalue of type const int. And a temporary of type const int gets initialized. So you have an xvalue denoting a temporary of type const int. And the reference r is bound to the resulting glvalue (i.e, r is binding to a xvalue denoting a temporary of type const int).
So as far as I can tell, the temporary that has been created is const-qualified.
Can we do const_cast<int &>(r) = 101; without triggering undefined behavior?
No, this undefined behavior by definition since you're trying to modify (write into) a read-only memory location:
[expr.const.cast]/6: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_­cast that casts away a const-qualifier can produce undefined behavior.
[dcl.type.cv]/4: Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const
object during its lifetime (3.8) results in undefined behavior.

Why do lvalue-to-rvalue conversions exist? Why are they required? [duplicate]

I see the term "lvalue-to-rvalue conversion" used in many places throughout the C++ standard. This kind of conversion is often done implicitly, as far as I can tell.
One unexpected (to me) feature of the phrasing from the standard is that they decide to treat lvalue-to-rvalue as a conversion. What if they had said that a glvalue is always acceptable instead of a prvalue. Would that phrase actually have a different meaning? For example, we read that lvalues and xvalues are examples of glvalues. We don't read that lvalues and xvalues are convertible to glvalues. Is there a difference in meaning?
Before my first encounter with this terminology, I used to model lvalues and rvalues mentally more or less as follows: "lvalues are always able to act as rvalues, but in addition can appear on the left side of an =, and to the right of an &".
This, to me, is the intuitive behavior that if I have a variable name, then I can put that name everywhere where I would have put a literal. This model seems consistent with lvalue-to-rvalue implicit conversions terminology used in the standard, as long as this implicit conversion is guaranteed to happen.
But, because they use this terminology, I started wondering whether the implicit lvalue-to-rvalue conversion may fail to happen in some cases. That is, maybe my mental model is wrong here. Here is a relevant part of the standard: (thanks to the commenters).
Whenever a glvalue appears in a context where a prvalue is expected, the glvalue is converted to a prvalue; see 4.1, 4.2, and 4.3. [Note: An attempt to bind an rvalue reference to an lvalue is not such a context; see 8.5.3 .—end note]
I understand what they describe in the note is the following:
int x = 1;
int && y = x; //in this declaration context, x won't bind to y.
// but the literal 1 would have bound, so this is one context where the implicit
// lvalue to rvalue conversion did not happen.
// The expression on right is an lvalue. if it had been a prvalue, it would have bound.
// Therefore, the lvalue to prvalue conversion did not happen (which is good).
So, my question is (are):
1) Could someone clarify the contexts where this conversion can happen implicitly? Specifically, other than the context of binding to an rvalue reference, are there any other where lvalue-to-rvalue conversions fail to happen implicitly?
2) Also, the parenthetical [Note:...] in the clause makes it seem that we could have figured it out from the sentence before. Which part of the standard would that be?
3) Does that mean that rvalue-reference binding is not a context where we expect a prvalue expression (on the right)?
4) Like other conversions, does the glvalue-to-prvalue conversion involve work at runtime that would allow me to observe it?
My aim here is not to ask if it is desirable to allow such a conversion. I'm trying to learn to explain to myself the behavior of this code using the standard as starting point.
A good answer would go through the quote I placed above and explain (based on parsing the text) whether the note in it is also implicit from its text. It would then maybe add any other quotes that let me know the other contexts in which this conversion may fail to happen implicitly, or explain there are no more such contexts. Perhaps a general discussion of why glvalue to prvalue is considered a conversion.
I think the lvalue-to-rvalue conversion is more than just use an lvalue where an rvalue is required. It can create a copy of a class, and always yields a value, not an object.
I'm using n3485 for "C++11" and n1256 for "C99".
Objects and values
The most concise description is in C99/3.14:
object
region of data storage in the execution environment, the contents of which can represent
values
There's also a bit in C++11/[intro.object]/1
Some objects are polymorphic; the implementation generates information associated with
each such object that makes it possible to determine that object’s type during program execution. For other objects, the interpretation of the values found therein is determined by the type of the expressions used to access them.
So an object contains a value (can contain).
Value categories
Despite its name, value categories classify expressions, not values. lvalue-expressions even cannot be considered values.
The full taxonomy / categorization can be found in [basic.lval]; here's a StackOverflow discussion.
Here are the parts about objects:
An lvalue ([...]) designates a function or an object. [...]
An xvalue (an “eXpiring” value) also refers to an object [...]
A glvalue (“generalized” lvalue) is an lvalue or an xvalue.
An rvalue ([...]) is an xvalue, a temporary object 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. [...]
Note the phrase "a value that is not associated with an object". Also note that as xvalue-expressions refer to objects, true values must always occur as prvalue-expressions.
The lvalue-to-rvalue conversion
As footnote 53 indicates, it should now be called "glvalue-to-prvalue conversion". First, here's the quote:
1 A glvalue of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program
that necessitates this conversion has undefined behavior. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.
This first paragraph specifies the requirements and the resulting type of the conversion. It isn't yet concerned with the effects of the conversion (other than Undefined Behaviour).
2 When an lvalue-to-rvalue conversion occurs in an unevaluated operand or a subexpression thereof the value contained in the referenced object is not accessed. Otherwise, if the glvalue has a class type, the conversion copy-initializes a temporary of type T from the glvalue and the result of the conversion is a prvalue for the temporary. Otherwise, if the glvalue has (possibly cv-qualified) type std::nullptr_t, the
prvalue result is a null pointer constant. Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
I'd argue that you'll see the lvalue-to-rvalue conversion most often applied to non-class types. For example,
struct my_class { int m; };
my_class x{42};
my_class y{0};
x = y;
The expression x = y does not apply the lvalue-to-rvalue conversion to y (that would create a temporary my_class, by the way). The reason is that x = y is interpreted as x.operator=(y), which takes y per default by reference, not by value (for reference binding, see below; it cannot bind an rvalue, as that would be a temporary object different from y). However, the default definition of my_class::operator= does apply the lvalue-to-rvalue conversion to x.m.
Therefore, the most important part to me seems to be
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
So typically, an lvalue-to-rvalue conversion will just read the value from an object. It isn't just a no-op conversion between value (expression) categories; it can even create a temporary by calling a copy constructor. And the lvalue-to-rvalue conversion always returns a prvalue value, not a (temporary) object.
Note that the lvalue-to-rvalue conversion is not the only conversion that converts an lvalue to a prvalue: There's also the array-to-pointer conversion and the function-to-pointer conversion.
values and expressions
Most expressions don't yield objects[[citation needed]]. However, an id-expression can be an identifier, which denotes an entity. An object is an entity, so there are expressions which yield objects:
int x;
x = 5;
The left hand side of the assignment-expression x = 5 also needs to be an expression. x here is an id-expression, because x is an identifier. The result of this id-expression is the object denoted by x.
Expressions apply implicit conversions: [expr]/9
Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue, array-to-pointer, or function-to-pointer standard conversions are applied to convert the expression to a prvalue.
And /10 about usual arithmetic conversions as well as /3 about user-defined conversions.
I'd love now to quote an operator that "expects a prvalue for that operand", but cannot find any but casts. For example, [expr.dynamic.cast]/2 "If T is a pointer type, v [the operand] shall be a prvalue of a pointer to complete class type".
The usual arithmetic conversions required by many arithmetic operators do invoke an lvalue-to-rvalue conversion indirectly via the standard conversion used. All standard conversions but the three that convert from lvalues to rvalues expect prvalues.
The simple assignment however doesn't invoke the usual arithmetic conversions. It is defined in [expr.ass]/2 as:
In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.
So although it doesn't explicitly require a prvalue expression on the right hand side, it does require a value. It is not clear to me if this strictly requires the lvalue-to-rvalue conversion. There's an argument that accessing the value of an uninitialized variable should always invoke undefined behaviour (also see CWG 616), no matter if it's by assigning its value to an object or by adding its value to another value. But this undefined behaviour is only required for an lvalue-to-rvalue conversion (AFAIK), which then should be the only way to access the value stored in an object.
If this more conceptual view is valid, that we need the lvalue-to-rvalue conversion to access the value inside an object, then it'd be much easier to understand where it is (and needs to be) applied.
Initialization
As with simple assignment, there's a discussion whether or not the lvalue-to-rvalue conversion is required to initialize another object:
int x = 42; // initializer is a non-string literal -> prvalue
int y = x; // initializer is an object / lvalue
For fundamental types, [dcl.init]/17 last bullet point says:
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. Standard conversions will be used, if necessary, to convert the initializer expression to the cv-unqualified version of the destination type; no user-defined conversions are considered. If the conversion cannot be done, the initialization is ill-formed.
However, it also mentioned the value of the initializer expression. Similar to the simple-assignment-expression, we can take this as an indirect invocation of the lvalue-to-rvalue conversion.
Reference binding
If we see lvalue-to-rvalue conversion as a way to access the value of an object (plus the creation of a temporary for class type operands), we understand that it's not applied generally for binding to a reference: A reference is an lvalue, it always refers to an object. So if we bound values to references, we'd need to create temporary objects holding those values. And this is indeed the case if the initializer-expression of a reference is a prvalue (which is a value or a temporary object):
int const& lr = 42; // create a temporary object, bind it to `r`
int&& rv = 42; // same
Binding a prvalue to an lvalue reference is prohibited, but prvalues of class types with conversion functions that yield lvalue references may be bound to lvalue references of the converted type.
The complete description of reference binding in [dcl.init.ref] is rather long and rather off-topic. I think the essence of it relating to this question is that references refer to objects, therefore no glvalue-to-prvalue (object-to-value) conversion.
On glvalues: A glvalue ("generalized" lvalue) is an expression that is either an lvalue or an xvalue.
A glvalue may be implicitly converted to prvalue with lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit conversion.
Lvalue transformations are applied when lvalue argument (e.g. reference to an object) is used in context where rvalue (e.g. a number) is expected.
Lvalue to rvalue conversion
A glvalue of any non-function, non-array type T can be implicitly converted to prvalue of the same type. If T is a non-class type, this conversion also removes cv-qualifiers. Unless encountered in unevaluated context (in an operand of sizeof, typeid, noexcept, or decltype), this conversion effectively copy-constructs a temporary object of type T using the original glvalue as the constructor argument, and that temporary object is returned as a prvalue. If the glvalue has the type std::nullptr_t, the resulting prvalue is the null pointer constant nullptr.

lvalue to rvalue implicit conversion

I see the term "lvalue-to-rvalue conversion" used in many places throughout the C++ standard. This kind of conversion is often done implicitly, as far as I can tell.
One unexpected (to me) feature of the phrasing from the standard is that they decide to treat lvalue-to-rvalue as a conversion. What if they had said that a glvalue is always acceptable instead of a prvalue. Would that phrase actually have a different meaning? For example, we read that lvalues and xvalues are examples of glvalues. We don't read that lvalues and xvalues are convertible to glvalues. Is there a difference in meaning?
Before my first encounter with this terminology, I used to model lvalues and rvalues mentally more or less as follows: "lvalues are always able to act as rvalues, but in addition can appear on the left side of an =, and to the right of an &".
This, to me, is the intuitive behavior that if I have a variable name, then I can put that name everywhere where I would have put a literal. This model seems consistent with lvalue-to-rvalue implicit conversions terminology used in the standard, as long as this implicit conversion is guaranteed to happen.
But, because they use this terminology, I started wondering whether the implicit lvalue-to-rvalue conversion may fail to happen in some cases. That is, maybe my mental model is wrong here. Here is a relevant part of the standard: (thanks to the commenters).
Whenever a glvalue appears in a context where a prvalue is expected, the glvalue is converted to a prvalue; see 4.1, 4.2, and 4.3. [Note: An attempt to bind an rvalue reference to an lvalue is not such a context; see 8.5.3 .—end note]
I understand what they describe in the note is the following:
int x = 1;
int && y = x; //in this declaration context, x won't bind to y.
// but the literal 1 would have bound, so this is one context where the implicit
// lvalue to rvalue conversion did not happen.
// The expression on right is an lvalue. if it had been a prvalue, it would have bound.
// Therefore, the lvalue to prvalue conversion did not happen (which is good).
So, my question is (are):
1) Could someone clarify the contexts where this conversion can happen implicitly? Specifically, other than the context of binding to an rvalue reference, are there any other where lvalue-to-rvalue conversions fail to happen implicitly?
2) Also, the parenthetical [Note:...] in the clause makes it seem that we could have figured it out from the sentence before. Which part of the standard would that be?
3) Does that mean that rvalue-reference binding is not a context where we expect a prvalue expression (on the right)?
4) Like other conversions, does the glvalue-to-prvalue conversion involve work at runtime that would allow me to observe it?
My aim here is not to ask if it is desirable to allow such a conversion. I'm trying to learn to explain to myself the behavior of this code using the standard as starting point.
A good answer would go through the quote I placed above and explain (based on parsing the text) whether the note in it is also implicit from its text. It would then maybe add any other quotes that let me know the other contexts in which this conversion may fail to happen implicitly, or explain there are no more such contexts. Perhaps a general discussion of why glvalue to prvalue is considered a conversion.
I think the lvalue-to-rvalue conversion is more than just use an lvalue where an rvalue is required. It can create a copy of a class, and always yields a value, not an object.
I'm using n3485 for "C++11" and n1256 for "C99".
Objects and values
The most concise description is in C99/3.14:
object
region of data storage in the execution environment, the contents of which can represent
values
There's also a bit in C++11/[intro.object]/1
Some objects are polymorphic; the implementation generates information associated with
each such object that makes it possible to determine that object’s type during program execution. For other objects, the interpretation of the values found therein is determined by the type of the expressions used to access them.
So an object contains a value (can contain).
Value categories
Despite its name, value categories classify expressions, not values. lvalue-expressions even cannot be considered values.
The full taxonomy / categorization can be found in [basic.lval]; here's a StackOverflow discussion.
Here are the parts about objects:
An lvalue ([...]) designates a function or an object. [...]
An xvalue (an “eXpiring” value) also refers to an object [...]
A glvalue (“generalized” lvalue) is an lvalue or an xvalue.
An rvalue ([...]) is an xvalue, a temporary object 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. [...]
Note the phrase "a value that is not associated with an object". Also note that as xvalue-expressions refer to objects, true values must always occur as prvalue-expressions.
The lvalue-to-rvalue conversion
As footnote 53 indicates, it should now be called "glvalue-to-prvalue conversion". First, here's the quote:
1 A glvalue of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program
that necessitates this conversion has undefined behavior. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.
This first paragraph specifies the requirements and the resulting type of the conversion. It isn't yet concerned with the effects of the conversion (other than Undefined Behaviour).
2 When an lvalue-to-rvalue conversion occurs in an unevaluated operand or a subexpression thereof the value contained in the referenced object is not accessed. Otherwise, if the glvalue has a class type, the conversion copy-initializes a temporary of type T from the glvalue and the result of the conversion is a prvalue for the temporary. Otherwise, if the glvalue has (possibly cv-qualified) type std::nullptr_t, the
prvalue result is a null pointer constant. Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
I'd argue that you'll see the lvalue-to-rvalue conversion most often applied to non-class types. For example,
struct my_class { int m; };
my_class x{42};
my_class y{0};
x = y;
The expression x = y does not apply the lvalue-to-rvalue conversion to y (that would create a temporary my_class, by the way). The reason is that x = y is interpreted as x.operator=(y), which takes y per default by reference, not by value (for reference binding, see below; it cannot bind an rvalue, as that would be a temporary object different from y). However, the default definition of my_class::operator= does apply the lvalue-to-rvalue conversion to x.m.
Therefore, the most important part to me seems to be
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
So typically, an lvalue-to-rvalue conversion will just read the value from an object. It isn't just a no-op conversion between value (expression) categories; it can even create a temporary by calling a copy constructor. And the lvalue-to-rvalue conversion always returns a prvalue value, not a (temporary) object.
Note that the lvalue-to-rvalue conversion is not the only conversion that converts an lvalue to a prvalue: There's also the array-to-pointer conversion and the function-to-pointer conversion.
values and expressions
Most expressions don't yield objects[[citation needed]]. However, an id-expression can be an identifier, which denotes an entity. An object is an entity, so there are expressions which yield objects:
int x;
x = 5;
The left hand side of the assignment-expression x = 5 also needs to be an expression. x here is an id-expression, because x is an identifier. The result of this id-expression is the object denoted by x.
Expressions apply implicit conversions: [expr]/9
Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue, array-to-pointer, or function-to-pointer standard conversions are applied to convert the expression to a prvalue.
And /10 about usual arithmetic conversions as well as /3 about user-defined conversions.
I'd love now to quote an operator that "expects a prvalue for that operand", but cannot find any but casts. For example, [expr.dynamic.cast]/2 "If T is a pointer type, v [the operand] shall be a prvalue of a pointer to complete class type".
The usual arithmetic conversions required by many arithmetic operators do invoke an lvalue-to-rvalue conversion indirectly via the standard conversion used. All standard conversions but the three that convert from lvalues to rvalues expect prvalues.
The simple assignment however doesn't invoke the usual arithmetic conversions. It is defined in [expr.ass]/2 as:
In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.
So although it doesn't explicitly require a prvalue expression on the right hand side, it does require a value. It is not clear to me if this strictly requires the lvalue-to-rvalue conversion. There's an argument that accessing the value of an uninitialized variable should always invoke undefined behaviour (also see CWG 616), no matter if it's by assigning its value to an object or by adding its value to another value. But this undefined behaviour is only required for an lvalue-to-rvalue conversion (AFAIK), which then should be the only way to access the value stored in an object.
If this more conceptual view is valid, that we need the lvalue-to-rvalue conversion to access the value inside an object, then it'd be much easier to understand where it is (and needs to be) applied.
Initialization
As with simple assignment, there's a discussion whether or not the lvalue-to-rvalue conversion is required to initialize another object:
int x = 42; // initializer is a non-string literal -> prvalue
int y = x; // initializer is an object / lvalue
For fundamental types, [dcl.init]/17 last bullet point says:
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. Standard conversions will be used, if necessary, to convert the initializer expression to the cv-unqualified version of the destination type; no user-defined conversions are considered. If the conversion cannot be done, the initialization is ill-formed.
However, it also mentioned the value of the initializer expression. Similar to the simple-assignment-expression, we can take this as an indirect invocation of the lvalue-to-rvalue conversion.
Reference binding
If we see lvalue-to-rvalue conversion as a way to access the value of an object (plus the creation of a temporary for class type operands), we understand that it's not applied generally for binding to a reference: A reference is an lvalue, it always refers to an object. So if we bound values to references, we'd need to create temporary objects holding those values. And this is indeed the case if the initializer-expression of a reference is a prvalue (which is a value or a temporary object):
int const& lr = 42; // create a temporary object, bind it to `r`
int&& rv = 42; // same
Binding a prvalue to an lvalue reference is prohibited, but prvalues of class types with conversion functions that yield lvalue references may be bound to lvalue references of the converted type.
The complete description of reference binding in [dcl.init.ref] is rather long and rather off-topic. I think the essence of it relating to this question is that references refer to objects, therefore no glvalue-to-prvalue (object-to-value) conversion.
On glvalues: A glvalue ("generalized" lvalue) is an expression that is either an lvalue or an xvalue.
A glvalue may be implicitly converted to prvalue with lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit conversion.
Lvalue transformations are applied when lvalue argument (e.g. reference to an object) is used in context where rvalue (e.g. a number) is expected.
Lvalue to rvalue conversion
A glvalue of any non-function, non-array type T can be implicitly converted to prvalue of the same type. If T is a non-class type, this conversion also removes cv-qualifiers. Unless encountered in unevaluated context (in an operand of sizeof, typeid, noexcept, or decltype), this conversion effectively copy-constructs a temporary object of type T using the original glvalue as the constructor argument, and that temporary object is returned as a prvalue. If the glvalue has the type std::nullptr_t, the resulting prvalue is the null pointer constant nullptr.