Let's imagine this function:
C* get(C* c, int offset) {
return c + offset;
}
I would like to know if a call to this function is evaluated as a prvalue:
C array_c[3];
C* c2 = get(array_c, 2);
Is get(array_c, 2)
a prvalue?
According to Value categories page on cppreference:
- a glvalue (“generalized” lvalue) is an expression whose evaluation determines the identity of an object, bit-field, or function;
- a prvalue (“pure” rvalue) is an expression whose evaluation either :
- computes a value that is not associated with an object
- creates a temporary object and denotes it
- an xvalue (an “eXpiring” value) is a glvalue that denotes an object or bit-field whose resources can be reused;
- an lvalue (so-called, historically, because lvalues could appear on the left-hand side of an assignment expression) is a glvalue that is not an xvalue;
In our example, the expression get(array_c, 2)
points to an already exising object that doesn't expire after the call. So we can say it is an lvalue. Moreover, we can write *get(array_c, 2) = C{};
to assign a value to the expression.
However, there are two points that make me think it is not an lvalue. First of all, in the same page of cppreference:
The following expressions are prvalue expressions:
- a function call or an overloaded operator expression, whose return type is non-reference
In our example, the get
function returns a non-reference so, according to this definition, the call should be evaluated as an prvalue.
Also, I'm wondering if get(array_c, 2)
is indeed a temporary that makes it a prvalue and *get(array_c, 2)
is an lvalue because we can assign a value to it.
What do you think? Is the function call evaluated as an lvalue, a prvalue (or something else)?
get(array_c, 2)
and *get(array_c, 2)
are two different expressions, and have different value categories.
get
returns pointer by value itself, then get(array_c, 2)
is considered as an rvalue (prvalue) expression. You can't perform assignment on it like get(array_c, 2) = nullptr;
or get address from it like &get(array_c, 2)
, it's just same as if get
returns other types like int
.
On the other hand, *get(array_c, 2)
is an lvalue expression. As you said you can perform assignment on it, which is valid or not, the returned pointer is valid or not doesn't matter.
*p
, the built-in indirection expression;
PS: Assignment might be performed on rvalues of class type; it's not an absolute condition for determining lvalue expressions or not.