I personally find that typedefs are very useful when dealing with templated code, both when writing templates, and when instantiating them.
Writing templates:
typedefs are required for template metaprogramming. For Example, removing const:
template<typename T>
struct RemoveConst
{
typedef T Type;
};
template<>
struct RemoveConst<const T>
{
typedef T Type;
};
Now, we can access the const-less type from any T by instantiating RemoveConst::Type
Instantiating templates:
Like a lot of things in programming, right tool for the right job.
typedefs such as your example
typedef std::list<Foobar> FoobarList;
...
FoobarList GetFoobars();
Sound completely reasonable, mainly because the typedefed name is descriptive(a FoobarList is a List of Foobars). This is very useful particularly when dealing with STL containers, or any other template types that share the same interface. imagine the following class declaration:
class SomeClass
{
...
std::vector<int> mContainer;
};
This class is likely to iterate over the elements of Container, which would result in code similar to:
for(std::vector<int>::iterator It = mContainer.begin(); It != mContainer.end(); ++It)
{
}
Now imagine that you realize, after writing the above for-loop in 5 different metods, that you are constantly inserting in the middle of the array, and that a std::list would be much better suited for the job.
In this case, you would have to go through every instance of std::vector::iterator, and change the declaration.
Instead, What you can do, is typedef the container you are using inside the class:
class SomeClass
{
typedef std::vector<int> IntContainer;
...
IntContainer mContainer;
};
This can allow you to write highly generic code, that can be very easily modifiable.
for(IntContainer::iterator It = mContainer.begin(); It != mContainer.end(); ++It)
{
}
In this case, you only need to change the typedef of IntContainer, and any instance that refers to it, is automatically changed.