In my years of C++ (MFC) programming in I never felt the need to use typedef, so I don't really know what is it used for. Where should I use it? Are there any real situations where the use of typedef is preferred? Or is this really more a C-specific keyword?

10 Answers
10

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:

For C++11, the addition of the "using a = b" syntax pleasantly leaves the "typedef" keyword mostly to memories, as typedef was always confusingly backwards and inconsistent with #define (now I never accidentally reverse the two because it's the same as variable assignment ordering).
–
Dwayne RobinsonJul 19 '14 at 1:12

Naturally you would use the uint32_t from <stdint.h> though right? :)
–
Greg RogersFeb 5 '09 at 15:55

And only for those cases, usually rare, where you need exactly 32 bits.
–
KeithBFeb 5 '09 at 16:49

6

@KeithB: I think the rarity depends on what type of development you do. Embedded systems developers and those dealing frequently with file formats are two cases I can think of when you will often need to know exact sizes.
–
j_random_hackerFeb 7 '09 at 1:05

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.

Can you discuss best practices on this for header files? The options seem to be putting the typedef in Froboz.h, which creates header dependency and long build times; putting the typedefs in Frobozfwd.h (per Effective C++), which seems a pain for maintainability (two headers for everything); or putting the typedefs in FroCommon.h, which kills reusability. Is there some better way?
–
Rob NapierMar 1 '10 at 14:17

Thanks. I've put a longer version of this question here: stackoverflow.com/questions/2356548/…. I fear I've come to the same conclusions so far, which is that there isn't really a good answer you can use consistently, which means it's hard to have a rule that everyone on the team can follow and rely on. "For this header you need to use the fwd version, but this header you just include the base header, and this related stuff is defined over here in common.h..." How does anyone ever write maintainable and reusable C++? (ObjC has spoiled me... :D)
–
Rob NapierMar 1 '10 at 14:58

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:

One good reason to use typedef is if the type of something may change. For example, let's say that for now, 16-bit ints are fine for indexing some dataset because for the foreseeable future, you'll have less than 65535 items, and that space constraints are significant or you need good cache performance. However, on the off chance that you need to use your program on a dataset with more than 65535 items, you want to be able to easily switch to a wider integer. Use a typedef, and you only have to change this in one place.

what if I want to change from int to say unsigned long? I would have to check all my source code for overflows etc... -> not a good reason to use a typedef! Use a wrapper interface instead.
–
xtoflFeb 5 '09 at 15:27

Or give the typedef a sensible name which indicates what properties (such as size and signedness) can be relied on, and then don't change it in a way that breaks those properties. stdint has some good models for how to do this, such as int_fast* and int_least*. No need for a big interface there.
–
Steve JessopFeb 6 '09 at 0:14

@xtofl: If you are worried about overflows, you would already be performing checks using numeric_limits<my_int>, and those checks will continue to Do The Right Thing when you change what my_int is typedef'd to.
–
j_random_hackerFeb 7 '09 at 1:28

If you just use int for indexing, the sizeof(int) usually corresponds to the bit'edness of the processor and is the limit on how much memory is indexable. So if you can use an int, you'll never be in this situation.
–
Joseph GarvinFeb 24 '09 at 13:41

Basically it allows you to create an alias for a type. When/if you have to change the type, the rest of the code could be unchanged (this depends on the code, of course).
For example let's say you want to iter on a c++ vector

In the future you may think to change the vector with a list, because the type of operations you have to do on it. Without typedef you have to change ALL occurrences of vector within your code.
But if you write something like this:

That's not a really good rationale of using typedefs: you should use an interface type for that (Abstract Data Type, if you prefer). That's why you needed to add the 'depends on the code'. It should be the code that depends on the type :)
–
xtoflFeb 5 '09 at 15:24

Next to that, v->begin() should become v.begin()...
–
xtoflFeb 5 '09 at 15:25

@xtofl: typedefs and interface types are both valid ways to solve this particular problem. Interface types are more general, but they are also more heavyweight. Also, correct use of interface types implies that all calls will be virtual -- a heavy price for iterator advancement/dereference.
–
j_random_hackerFeb 7 '09 at 1:19

typedef allows to not only have an alias for complex types, but gives you an natural place to document a type. I sometimes use it for documentational purposes.

There are also times when I use an array of bytes. Now, an array of bytes could mean a lot of things. typedef makes it handy to define my byte array as "hash32", or "fileContent" to make my code more readable.

I don't think that will compile. Do you maybe mean "void doStuff( typename A<_T>::T _value );"? (You need the typename keyword in there because the compiler will interpret A<_T>::T as a member variable name otherwise.)
–
j_random_hackerFeb 7 '09 at 1:09