Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


Tip of the Day
Language: C++
Expertise: Intermediate
Sep 20, 2005

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++ doesallow 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 four 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 challengers)
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 challengers)
{
   static int scoreCard[playersCount];
   return scoreCard[challengers];
}
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 easy to see how to retrieve a score, but how does the assignment work? First, you make a refererence to Fred's score, then the assignment 18 is made to this reference. Not too difficult when you understand how the evaluation takes place and in what order.

If the function returned a pointer, 18 would be assigned to the pointer rather than to the memory address to which the pointer refers. Again, if you returned an int, 18 would never be assigned to the scoreCard array. That is why a function call is an Lvalue only if the result type is a reference. As you can see, references are not merely syntactic sugar or another way of expressing pointers, but were designed into the language by necessity to correctly hande cases such as this.

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 challengers)
{
     static int scoreCard[playersCount];
     return scoreCard[challengers];
}

int main()
{
     scores(Fred)  = 5;
     scores(Paul)  = 10;
     scores(Jim)   = 15;
     scores(Allen) = 20;

     cout << scores(Fred)  << " " << endl;
     cout << scores(Paul)  << " " << endl;
     cout << scores(Jim)   << " " << endl;
     cout << scores(Allen) << " " << endl;

     return 0;
}
Ron Stevenhaagen
 
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap