I have to say, there isn't much use for macros in C++. I mean, you can just use inline functions and templates, and they are type safe, not to mention they can be debugged easier.
There is a definite use for macros in C++, even though the "pure" scholars try to deny it. For example, you might have a very common kind of loop with the same instructions done at the start and end every time. Would you rather write:Code: [Select]
Code:
// ...for ( ... ; ... ; ... ) { // ... actual_code_unique_to_this_particular_loop; // ...}// ...
Or, with the use of macros, you could:Code: [Select]
Code:
#define BEGIN_LOOP(args) ...; for ( ... ; ... ; ...) {#define END_LOOP(args) ...; } ...;BEGIN_LOOP(args) actual_code_unique_to_this_particular_loop;END_LOOP(args)
Macros are low-level and have some severe limitations, but since they're purely text-based and work entirely outside of C++, you can do some very useful things that would simply not be possible in C++. How would you declare a new scope and fill it with user-supplied code (see example above) in C++?
The whole reason people use them these days is for reducing code redundancy and improving code readability and maintainability. Personally, while making a program relying heavily on arrays and maps and being able to traverse the elements of these, I felt the need for a
foreach statement in C++. Of course there isn't one, and there's no way to implement one inside of C++ (that looks pretty, anyway). But with macros, you can usually hide away all the nitty-gritty details inside a simple
for statement, giving:Code: [Select]
Code:
#define foreach(type, item, container) for ( ... ; ... ; ... )foreach( int, value, some_array ) { printf("%d\n", value);}
Not perfect, and the foreach macro wouldn't behave exactly like C++ (no space allowed between foreach and the opening parenthesis, for example), but you have to admit that's pretty damn more handy to code than manually messing with iterators or Microsoft's POSITION values every time you just want to simply step through all items in a container. This simple solution would not be possible without preprocessor macros.
That having been said, there are plenty of ways to use macros badly. But I usually say that as long as each macro keeps a clear semantic meaning, they do not obstruct debugging (unlike macros that have you wondering "what the hell does this do?"). Special care must of course be taken too, so you don't clutter up the variable name space with "hidden" variables declared from inside macros; these are much harder to debug, of course. An ideal macro does what it appears to do, and nothing else.
As for type safety, well, I usually say that macros should never be used in situations complex enough for type safety to become an issue. That having been said, ironically templates are often used to get
around type restrictions, i.e. have them act more like macros which accept anything, and let the compiler gawk if it doesn't work with the underlying code.