When should I use typedef in C++?

Template Metaprogramming

typedef is necessary for many template metaprogramming tasks -- whenever a class is treated as a "compile-time type function", a typedef is used as a "compile-time type value" to obtain the resulting type. E.g. consider a simple metafunction for converting a pointer type to its base type:

template<typename T>
struct strip_pointer_from;

template<typename T>
struct strip_pointer_from<T*> {   // Partial specialisation for pointer types
    typedef T type;
};

Example: the type expression strip_pointer_from<double*>::type evaluates to double. Note that template metaprogramming is not commonly used outside of library development.

Simplifying Function Pointer Types

typedef is helpful for giving a short, sharp alias to complicated function pointer types:

typedef int (*my_callback_function_type)(int, double, std::string);

void RegisterCallback(my_callback_function_type fn) {
    ...
}

In Bjarne's book he states that you can use typedef to deal with portability problems between systems that have different integer sizes. (this is a paraphrase)

On a machine where sizeof(int) is 4 you can

typedef int int32;

Then use int32 everywhere in your code. When you move to an implementation of C++ where sizeof(int) is 2, then you can just change the typdef

typedef long int32;

and your program will still work on the new implementation.


use with function pointer

Hide Function Pointer Declarations With a typedef

void (*p[10]) (void (*)() );

Only few programmers can tell that p is an "array of 10 pointers to a function returning void and taking a pointer to another function that returns void and takes no arguments." The cumbersome syntax is nearly indecipherable. However, you can simplify it considerably by using typedef declarations. First, declare a typedef for "pointer to a function returning void and taking no arguments" as follows:

  typedef void (*pfv)();

Next, declare another typedef for "pointer to a function returning void and taking a pfv" based on the typedef we previously declared:

 typedef void (*pf_taking_pfv) (pfv);

Now that we have created the pf_taking_pfv typedef as a synonym for the unwieldy "pointer to a function returning void and taking a pfv", declaring an array of 10 such pointers is a breeze:

  pf_taking_pfv p[10];

from


Just to provide some examples for the things said: STL containers.

 typedef std::map<int,Froboz> tFrobozMap;
 tFrobozMap frobozzes; 
 ...
 for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
 {
     ...
 }

It is not unusual to even use typedefs like

typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;

Another example: using shared pointers:

class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;

[update] As per comment - where to put them?

The last example - using shared_ptr - is easy: are true header material - or at least a forward header. You do need the forward declaration for shared_ptr anyway, and one of its declared advantages is that it's safe to use with a forward decl.

Put it another way: If there is a shared_ptr you probably should use the type only through a shared_ptr, so separating the declarations doesn't make much sense.

(Yes, xyzfwd.h is a pain. I'd use them only in hotspots - knowing that hotspots are hard to identify. Blame the C++ compile+link model...)

Container typedefs I usually use where the container variable is declared - e.g. locally for a local var, as class members when the actual container instance is a class member. This works well if the actual container type is an implementation detail - causing no additional dependency.

If they become part of a particular interface, they are declared together with the interface they are used with, e.g.

// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes); 

That gets problematic when the type is a binding element between different interfaces - i.e. the same type is needed by multiple headers. Some solutions:

  • declare it together with the contained type (suitable for containers that are frequently used for this type)
  • move them to a separate header
  • move to a separate header, and make it a data class where the actual container is an implementation detail again

I agree that the two latter aren't that great, I'd use them only when I get into trouble (not proactively).