how can a function name be an lvalue?

take this function:

1
2
3
4
int abs(int a)
{
     return a < 0 ? -a : a;
}


abs is supposed to be an lvalue but it cannot be assigned!!

1
2
int xy(int);
abs = xy;         // will not compile 



the same problem occurs with string literals.

Am I misunderstanding something?

Regards,
Juan
I don't know if it has ever been true that all lvalues can be put on the left-hand side of an assignment but it's certainly not the case in C++.

I think a more accurate way to think about it (without drowning in standardese) is that rvalues refer to things that are about to get destroyed (e.g. temporaries) or that are no longer needed (things that you've called std::move on) while lvalues are more long-lived (it will still be valid to use them afterwards in the same scope).

Your function abs will not get destroyed, only objects get destroyed, so I would say it's "long-lived". You cannot assign to it but that's just because the assignment operator is not defined for functions.

String literals are arrays. Those arrays stays alive for the whole program. You are not allowed to assign to them because arrays cannot be assigned to. Even if you could assign to arrays you wouldn't be able to assign to string literals because those arrays are const.
Last edited on
Note that class objects can often be assigned to even if they're rvalues.

 
std::string() = ""; // useless but valid 

The reason for this is that the assignment operator is technically just a member function, and you are allowed to call member functions on rvalues, even non-const ones.
Last edited on
yes but what would be the meaning of this assignment?
It's totally meaningless. I just mentioned it to show that lvalues and rvalues have very little to do with which side of an assignment they're allowed.

But do note that for non-class types this sort of code is not allowed.

 
int() = 7; // error 
Last edited on
See this table that describes the C++17 taxonomy for value categories:
mbozzi wrote:
| Value category | Fundamental? | Has identity?  | Can be moved from? |
|----------------+--------------+----------------+--------------------|
| lvalue         | yes          | yes            | no                 |
| xvalue         | yes          | yes            | yes                |
| prvalue        | yes          | no             | yes                |
|----------------+--------------+----------------+--------------------|
| glvalue        | no           | yes            | doesn't matter     |
| rvalue         | no           | doesn't matter | yes                |

It's from an earlier thread:
https://cplusplus.com/forum/general/285146/#msg1237482

Functions can't be moved from. And since functions have unique addresses, I think they are considered to have "identity" too. So expressions like abs should be lvalues according to the table.

Back in 2020 we talked about that expressions with function type can be used to initialize rvalue references:
https://cplusplus.com/forum/general/273175/#msg1178129
At that time I speculated that the exception to the rule existed to ease generic programming, and my opinion hasn't changed. The distinction between rvalue and lvalue doesn't seem to be important for functions.
Last edited on
Am I misunderstanding something?


Almost probably - and going down a rabbit hole! :) :)

In my mind (and the language lawyers will probably squawk), a function is an lvalue if it returns a ref - otherwise if it returns a value it's an rvalue.

Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

int rv(int a) {
	return a;
}

int& lv() {
	static int s { };

	return s;
}

int main() {
	const auto f1 { rv(6) };
	const auto f2 { lv() };

	lv() = 5;

	const auto f3 { lv() };

	std::cout << "f1: " << f1 << '\n';
	std::cout << "f2: " << f2 << '\n';
	std::cout << "f3: " << f3 << '\n';
}


which displays:


f1: 6
f2: 0
f3: 5


> how can a function name be an lvalue?

From http://eel.is/c++draft/basic.lval#1

A glvalue is an expression whose evaluation determines the identity of an object or function.

The name of a function (when used as an expresson) is a glvalue

An xvalue is a glvalue that denotes an object whose resources can be reused (usually because it is near the end of its lifetime).

The name of a function is not an xvalue

An lvalue is a glvalue that is not an xvalue

Ergo, The name of a function (when used as an expresson) is an lvalue

Note:
Historically, lvalues and rvalues were so-called because they could appear on the left- and right-hand side of an assignment (although this is no longer generally true); glvalues are “generalized” lvalues, prvalues are “pure” rvalues, and xvalues are “eXpiring” lvalues. Despite their names, these terms classify expressions, not values.

http://eel.is/c++draft/basic.lval#3
seeplus wrote:
In my mind (and the language lawyers will probably squawk), a function is an lvalue if it returns a ref - otherwise if it returns a value it's an rvalue.

I think this is mostly correct except that a function call that returns an rvalue reference is actually an rvalue (an xvalue to be precise).

But now we're talking about function calls.

Juan's original question was about using the name of the function as an expression without calling it.
Last edited on
Topic archived. No new replies allowed.