String literals are arrays - objects of inherently unpredictable size (i.e of user-defined and possibly large size). In general case, there's simply no other way to represent such literals except as objects in memory, i.e. as lvalues
. In C99 this also applies to compound literals, which are also lvalues
.
Any attempts to artificially hide the fact that string literals are lvalues
at the language level would produce a considerable number of completely unnecessary difficulties, since the ability to point to a string literal with a pointer as well as the ability to access it as an array relies critically on its lvalue-ness being visible at the language level.
Meanwhile, literals of scalar types have fixed compile-time size. At the same time, such literals are very likely to be embedded directly into the machine commands on the given hardware architecture. For example, when you write something like i = i * 5 + 2
, the literal values 5
and 2
become explicit (or even implicit) parts of the generated machine code. They don't exist and don't need to exist as standalone locations in data storage. There's simply no point in storing values 5
and 2
in the data memory.
It is also worth noting that on many (if not most, or all) hardware architectures floating-point literals are actually implemented as "hidden" lvalues
(even though the language does not expose them as such). On platforms like x86 machine commands from floating-point group do not support embedded immediate operands. This means that virtually every floating-point literal has to be stored in (and read from) data memory by the compiler. E.g. when you write something like i = i * 5.5 + 2.1
it is translated into something like
const double unnamed_double_5_5 = 5.5;
const double unnamed_double_2_1 = 2.1;
i = i * unnamed_double_5_5 + unnamed_double_2_1;
In other words, floating-point literals
often end up becoming "unofficial" lvalues
internally. However, it makes perfect sense that language specification did not make any attempts to expose this implementation detail. At language level, arithmetic literals
make more sense as rvalues
.
alias<T[N]> {}
is possible now.U {}.arr
is also an rvalue of array type ifarr
is declared as such in the class definition forU
. – Theater&
operator". I suspect that definition is actually equivalent to the standard's definition, unless I'm missing something... – Braga&
, but are lvalues. Also, I'm rather unclear on why it's (presumably) invalid to apply&
to the return value of a function, which is specified to have object type... – Bragaregister
class. However I think (it's been a long time) I was trying to get at that with "syntactically valid". – Braga&"hello"
is valid C++. Hence, they should be l-values. – Pannonia