According to Christopher Strachey’s paper The Varieties of Programming Language on denotational semantics, in any programming languages names can be bound to bindable values, which is represented by the function environment: Id -> D
, where Id
are names (a.k.a. identifiers) and D
are denotations (a.k.a. bindable values). If the language has an assignment command, the assignable value denoted by a name can vary inside the lexical scope of the name through assignment, but the location holding the assignable value remains constant, so to keep the environment static, only locations are considered as bindable values (i.e. D
includes L
but not V
), and the dynamic part that associates locations to assignable values is represented by the function state: L -> V
, where L
are locations (a.k.a. L-values) and V
are stored values (a.k.a. R-values, contents, or assignable values).
In C++, functions names cannot be assigned to so they don’t denote locations (i.e. function values F
are not included in V
but in D
, that is D = L + F + …
):
void f(); // binding
void g(); // binding
int main() {
f = g; // assignment fails
return 0;
}
Output of clang++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
:
main.cpp:5:7: error: non-object type 'void ()' is not assignable
f = g; // assignment fails
~ ^
1 error generated.
Yet according to the C++ standard, function names are classified as L-value expressions (bold emphasis mine):
- A glvalue is an expression whose evaluation determines the identity of an object or function.
- A prvalue is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv
void
.- An xvalue is a glvalue that denotes an object whose resources can be reused (usually because it is near the end of its lifetime).
- An lvalue is a glvalue that is not an xvalue.
- An rvalue is a prvalue or an xvalue.
Why?