Solution

I l @ ve RuBoard

graphics/bulb.gif

Typedef : Controlling What's in a Name

To recap, writing typedef allows you to assign another equivalent name for a type. For example,

 typedef vector< vector<int> > IntMatrix; 

lets you write the simpler IntMatrix in place of the more verbose vector< vector<int> > .

1. Why use typedef ? Name as many situations/reasons as you can.

Here are several " abilities ."

Typeability

Shorter names are easier to type.

Readability

Typedef s can make code, especially long template type names, much more readable. For a simple example, a public newsgroup posting asked what the following code meant :

 int ( *t(int) )( int* ); 

If you're used to reading C declarations just like you'd read a Victorian English novel (that is, dense and verbose prose that at times feels like slogging through ankle-deep sucking muck), you know the answer and you're fine. If you're not, typedef s really help, even with as meaningless a typedef name as Func :

 typedef int (*Func)( int* ); Func t( int ); 

Now it's clearer that this is a function declaration, for a function named t that takes an int and returns a pointer to a function that takes an int* and returns an int . (Say that three times fast.) In this case, the typedef is easier to read than the English.

Typedef s can also add semantic meaning. For example, " PhoneBook " is much easier to understand than " map< string, string> ," where the latter has little semantic content and could mean nearly anything.

Communication

Typedef s can help to communicate intent. For example, instead of littering the program with lots of unadorned int s, it can be clearer to give the types names, even though at heart they still are just int s. Compare this:

 int x; int y; y = x * 3;   // might be okay -- who knows? 

with this:

 typedef int Inches; typedef int Dollars; Inches  x; Dollars y; y = x * 3;   // hmmm...? 

Which would you prefer to read if you were the maintenance programmer?

Portability

If you use typedef 'd names for platform-specific or otherwise nonportable names, you'll find it easier to move to new platforms. After all, it's easier to write this:

 #if defined USING_COMPILER_A   typedef __int32 Int32;   typedef __int64 Int64; #elif defined USING_COMPILER_B   typedef int       Int32;   typedef long long Int64; #endif 

than search-and-replace for one of the system-specific names throughout your code. The typedef names help to insulate your code from simple platform dependencies. (For reasons why you might not want to use #define for this purpose, however, turn to Item 35.)

2. Why is typedef such a good idea in code that uses standard (STL) containers?

Flexibility

Changing a typedef name in one place is easier than changing all its uses throughout the code. For example, consider the following code:

 void f( vector<Customer>& custs ) {   vector<Customer>::iterator i = custs.begin();   ... } 

What if, a few months later, we find out that vector isn't the right container after all? If we're storing huge quantities of Customer objects, the fact that vector 's storage is contiguous [2] may be a disadvantage and we might like to switch to deque instead. Or if we find ourselves frequently inserting/removing elements from the middle, we might like to switch to list instead.

[2] See Item 7.

In the above code, we'd have to make that change everywhere the type name " vector<Customer> " appears. How much easier it would be if we had only written:

 typedef vector<Customer> Customers; typedef Customers::iterator CustIter; ... void f( Customers& custs ) {   CustIter i = custs.begin();   ... } 

and only needed to change the typedef to list<Customer> or deque<Customer> ! Of course, it is not always this easy ”for example, our code might be rely- ing on the Customers::iterator being a random-access iterator, which a list<Customer>::iterator is not. But the typedef still insulates us from a lot of tedious changes that would be necessary otherwise.

Traitability

The traits idiom is a powerful way to associate information with a type, and if you want to customize standard containers or algorithms, you'll often need to provide traits. See the coverage of traits in the Generic Programming section of this book, and consider also the case-insensitive string example from Exceptional C++ [Sutter00] Items 2 and 3, where we defined our own char_traits replacement.

Summary

Most uses of typedef fall into one of these categories. In general, typedef makes code easier to write, easier to read, and easier to change through the proverbial "additional level of indirection" ”in this case, an indirection in name only is still as sweet.

I l @ ve RuBoard


More Exceptional C++
More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions
ISBN: 020170434X
EAN: 2147483647
Year: 2001
Pages: 118
Authors: Herb Sutter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net