79

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?

djeidot
  • 4,542
  • 4
  • 42
  • 45

13 Answers13

91

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) {
    ...
}
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
  • 2
    Necessary? Care to give an example? I can't think of any cases where it'd be necessary. – jalf Feb 05 '09 at 15:11
  • 13
    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 Robinson Jul 19 '14 at 01:12
40

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.

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
Restore the Data Dumps
  • 38,967
  • 12
  • 96
  • 122
  • 13
    Naturally you would use the uint32_t from though right? :) – Greg Rogers Feb 05 '09 at 15:55
  • And only for those cases, usually rare, where you need exactly 32 bits. – KeithB Feb 05 '09 at 16:49
  • 7
    @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_hacker Feb 07 '09 at 01:05
23

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

yesraaj
  • 46,370
  • 69
  • 194
  • 251
18

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).

Eva
  • 4,397
  • 5
  • 43
  • 65
peterchen
  • 40,917
  • 20
  • 104
  • 186
  • 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 Napier Mar 01 '10 at 14:17
  • 1
    Thanks. I've put a longer version of this question here: http://stackoverflow.com/questions/2356548/header-file-best-practices-for-typedefs. 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 Napier Mar 01 '10 at 14:58
6

typedef is useful in a lot of situations.

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

vector<int> v;

...

for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

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:

typedef vector<int> my_vect;

my_vect v;

...

for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

Now you just have to change one row of code (i.e from "typedef vector<int> my_vect" to "typedef list<int> my_vect") and everything works.

typedef also saves you time when you have complex data structures which are very long to write (and difficult to read)

Emiliano
  • 22,232
  • 11
  • 45
  • 59
  • 1
    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 :) – xtofl Feb 05 '09 at 15:24
  • And C++0x is coming! AWW-TO! AWW-TO! AWW-TO! – David Thornley Feb 05 '09 at 15:38
  • 3
    @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_hacker Feb 07 '09 at 01:19
5

typedef allows to not only have an alias for complex types, but gives you a natural place to document a type. I sometimes use it for documentation 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.

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
Ztyx
  • 14,100
  • 15
  • 78
  • 114
5

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.

dsimcha
  • 67,514
  • 53
  • 213
  • 334
  • 1
    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. – xtofl Feb 05 '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 Jessop Feb 06 '09 at 00:14
  • @xtofl: If you are worried about overflows, you would already be performing checks using numeric_limits, and those checks will continue to Do The Right Thing when you change what my_int is typedef'd to. – j_random_hacker Feb 07 '09 at 01: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 Garvin Feb 24 '09 at 13:41
2

There is one another use case to use typedef is when we want to enable a kind of Container Independent code (but not exactly!)

Let us say you have class:

Class CustomerList{

public:
    //some function
private:
    typedef list<Customer> CustomerContainer;
    typedef CustomerContainer::iterator Cciterator;
};

The above code encapsulates the internal container implementation using typedef and even if in future the list container needs to changed to vector or deque still the user of the CustomerList class doesn't need to worry about exact container implementation.

Hence, the typedef encapsulates and somewhat help us to write Container Independent code

2

Real-world uses of typedef:

  • providing friendly aliases for long-winded templated types
  • providing friendly aliases for function pointer types
  • providing local labels for types, e.g.:

    template<class _T> class A
    {
        typedef _T T;
    };
    
    template<class _T> class B
    {
        void doStuff( _T::T _value );
    };
    
xtofl
  • 40,723
  • 12
  • 105
  • 192
moonshadow
  • 86,889
  • 7
  • 82
  • 122
  • 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_hacker Feb 07 '09 at 01:09
0

Typedef allows flexibility in your class. When you want to change the data type in the program, you do not need to change multiple locations but just need to change one occurrence.

typedef <datatype example  int or double> value_type

you can give nay name instead of value_type, but value_type is normally the standard name.

So u can use typedef like

value_type i=0;     //same as a int or double i=0; 
zx485
  • 28,498
  • 28
  • 50
  • 59
sneha
  • 819
  • 7
  • 7
0

Whenever it makes the source clearer or better to read.

I use kind of typedef in C# for generics/templates. A "NodeMapping" is just better to read/use and understand then a lot of "Dictionary<string, XmlNode>". IMHO. So I'd recommend it for templates.

Leonidas
  • 2,440
  • 15
  • 22
0

1 practical example of typedef is size_t. It is guaranteed to be big enough to contain the size of the biggest object the host system can handle. The maximum permissible size is dependent on the compiler; if the compiler is 32 bits then it is simply a typedef for unsigned int but if the compiler is 64 bits then it would be a typedef for unsigned long long. The size_t data type is never negative.

Syscall
  • 19,327
  • 10
  • 37
  • 52
Rana Vivek
  • 126
  • 2
-2

... and you Don't Need a Typedef for an enum or a struct.

Or do you?

typedef enum { c1, c2 } tMyEnum;
typedef struct { int i; double d; } tMyStruct;

can be better written as

enum tMyEnum { c1, c2 }
struct  tMyStruct { int i; double d; };

Is that correct? What about C?

xtofl
  • 40,723
  • 12
  • 105
  • 192