Hacker News new | past | comments | ask | show | jobs | submit login

Protip #1: don't use them.



In C++, probably never. In C, they can be necessary for doing type orthogonal things (like intrusive data structures). Type generic expressions in C11 can be a bit of a safer alternative for some stuff, but you generally need to give explicit implementations for each type.

For example,

    #define sqrt(x) _Generic((x), long double: sqrtl, float: sqrtf, default: sqrt)(x)


Even in C++, they are good when you want to encapsulate a statement that may return from the enclosing function. Every time I write a parser or interpreter in C++, I end up writing a macro like

    #define EXPECT_TYPE(node, Type) if ((node)->type != Type) { return FAIL; }
and using it extensively.


Also things like generating code at compile time, but a lot of people could argue it both ways.


You have to use preprocessor in any non-trivial C++ project. For an idiomatic and very nice and clean example of a heavy preprocessor use see LLVM and Clang code.


You don't have to use the preprocessor, but it is definitely practical for certain things. It's probably not clear from my comment, but macros were what I assumed the above post was talking about though (e.g. min/max). FYI, some projects actually eschew the C/C++ preprocessor for other languages.

I tend to avoid macros, but stuff like generating things at compile time can sometimes be pretty useful. It can make it harder for other people to read the code if they're not familiar with it though (also any tools that need to parse), which is why I try to prefer using UltiSnips for most stuff I normally might do with a macro.


If you want a dense, readable, maintainable code - you're out of options, you have to resort to the preprocessor.

Any kind of repeating lists (enum + a switch over all the values, for example) are best handled by define-include-undefine sequences.

See how it is done in LLVM, see all the .def files there. I cannot think of a single viable alternative to this method.

And it is far from a "code generation", just merely listing things in a consistent manner.


> Any kind of repeating lists (enum + a switch over all the values, for example) are best handled by define-include-undefine sequences.

> See how it is done in LLVM, see all the .def files there. I cannot think of a single viable alternative to this method.

I've seen x-macros. I'm not sure I've seen them used to good effect, but I'd definitely be curious how the llvm code uses them.

> If you want a dense, readable, maintainable code - you're out of options, you have to resort to the preprocessor.

I guess it wasn't entirely obvious from my comment, but I wasn't arguing against using the preprocessor. It's self-contained, mostly usable with common tools, etc.. Anything that's supported on more than one platform or has compile time options generally depends on it. Dense, readable, maintainable code is definitely a good thing, which is one of the reasons I'd personally like to see a usable reflection land in C++.


> which is one of the reasons I'd personally like to see a usable reflection land in C++.

Of course. Reflection and proper macros. At least something like mbeddr would have been great.

I never said preprocessor is the best possible option. I'm only saying that at the moment it is the only practically available option, and therefore it's unavoidable, like it or not. I personally hate it with a passion, but I have to use it extensively.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: