Using a Function Call as an Lvalue

An Lvalue is an expression that can appear on the left-hand side of an equals sign. Likewise, an Rvalue expression appears on the right-hand side of the equals sign. Therefore the assignment statement takes the following form:

          Lvalue = Rvalue

The most common Lvalue expression is a variable name as follows:

          int x = 7;      // x is an Lvalue

Suppose you make x a constant. It is still considered to be an Lvalue. However, because you cannot change a constant value, it is referred to as a non-modifiable Lvalue:

          const int x = 7;      // ok initialze x with a const value
                         x = 8;      // error attempting to assign to a non modifiable Lvalue

Is it possible to make an assignment to a function call for example:

          foo(7) = 24;

At first glance, this makes no sense—a function isn't a variable, so how can you assign 24 to it? Actually, C++ does allow this, and it makes sense when you understand the mechanics behind how this expression is reduced. There is one rule in the C++ standard that states: "A function call is an Lvalue only if the result type is a reference." So, if the function prototype for foo is:

          int& foo(int);

Then the expression above is legal C++.

Here's an example of how you might apply this. Suppose you want to keep track of 4 players' scores. First, you define an enumeration of the players' names to use as an index into an array of scores as follows:

          enum players { Fred, Paul, Jim, Allen, playersCount // count of players };

Next, define the prototype for the function to which you wish to assign the scores:

          int& scores(players player)

Notice that the result type of the function is a reference, so the function may be used as an Lvalue. Now, you just need to define the function as follows:

int& scores( players player)
{
    static int scoreCard[playersCount];
    return scoreCard[player];
}

The function has a static array that holds the scores and returns the score of the player you pass as an argument. You may assign and retrieve a score as follows:

int fredsScore;
scores(Fred) = 18;
fredsScore = scores(Fred);

It's obvious how a score is retrieved, but how does the assignment work? An assignment is being made to the return type in the function. If you look at the return statement a reference is made to Fred's score, then the assignment 18 is made to this reference.

Here is the complete source code for the scores program:

#include<iostream>

using namespace std;

enum players
{
     Fred, Paul, Jim, Allen,
     playersCount // count of players
};

int& scores( players player)
{
     static int scoreCard[playersCount];
     return scoreCard[player];
}

int main()
{
     scores(Fred) = 5;
     scores(Paul) = 10;

     cout << scores(Fred) << endl;
     cout << scores(Paul) << endl;
     cout << (scores(Jim) = 15) << endl;
     cout << (scores(Allen) = 20) << endl;

    return 0;
}