It's important to be precise about what we're talking about.
- In C++, an expression has a type, and can be either an lvalue or rvalue (value category)
- An implicit conversion occurs when an expression of one (type, value category) occurs in a context where a different (type, value category) is expected.
- An explicit conversion uses one of the language's cast operators, taking a subexpression of one (type, value category) as an operand, and yielding an expression of a different (type, value category) as the result.
An lvalue or xvalue can be implicitly converted to a prvalue; this is called the lvalue-to-rvalue conversion for historical reasons. The line
int z = x + y;
serves as an example of this implicit conversion. As the comment explains, the built-in +
operator expects prvalues as its operands but we have supplied lvalues instead, so an implicit conversion occurs.
An lvalue can also be explicitly converted to an xvalue:
std::string s1 = static_cast<std::string&&>(s2); // i.e., std::move(s2)
Here s2
is an lvalue but we want to make sure the initializer is an xvalue so that the move constructor will be used, so we perform an explicit conversion.
An rvalue can be neither implicitly nor explicitly converted to an lvalue. For example, the following does not compile:
3++;
because the ++
operator requires an lvalue, and we have supplied an rvalue. Nor will the following compile, where we attempt to explicitly convert an rvalue to an lvalue:
static_cast<int&>(3)++;
(Note: the type of 3
is int
, not const int
. Constness is not the reason why we cannot modify 3
.)
There is actually no conversion occurring in the assignments shown:
x = 5;
y = 6;
because when assigning to an int
lvalue, a prvalue is expected as the right-hand operand, and a prvalue has been supplied. Although we are doing some sort of operation that has an rvalue as the source and an lvalue as the destination, this is not a conversion according to the rules of the language.