I like to keep an eye on new developments of the C++ spec and the direction the language is moving, but in the code for Rival Fortress I don’t use most of the features that C++ has to offer.
The features I don’t like
I rarely use inheritance, and if I use it, I stay away from virtual functions or deep hierarchies. I find the code to be cleaner and easier to understand when one doesn’t need to study deep class hierarchies to figure out what a piece of code is doing.
I’m also not a big fan of the Standard Library as I find that most of the functionality it provides is either less performant than ad-hoc implementations or tends to hide complexity that I’d rather have out in the open.
I rarely use templates as most of the problems they address can be solved with code generation as I talked about in my reflection preprocessor post. Templates also bloat compile times considerably and produce god-awful compiler error messages.
I never use exceptions as I find them to be a useless performance penalty that can be easily avoided with careful coding. They also increase code complexity because of all the redundant
catch blocks that tend to pollute codebases that use them.
I don’t use RAII and very rarely use object constructor/destructor pairs. I find that RAII is unnecessary when coding in a functional style.
The features I like
Most of my code is C99-like, with the exception of the following features that I found useful:
- Operator overloading: when it makes sense, like for simple vector math (i.e. addition, subtraction, scalar multiplication).
- Function overloading: I try to use self-documenting function names, but I find that in C the lack of function overloading can force you to either use verbose or cryptic names when the same logical function needs to operate on different data types.
- const_expr: is sometimes useful when I don’t want to go the macro route and need something to be evaluated at compile time. For example, string length and string hashing have both a runtime and a
- static_assert: I find it very useful especially for sanity checks and paired with
const_exprfunctions or for validation of meta programmed code generated by the engine’s preprocessor.
- raw string literals: are very useful when dealing with long string. I use them very often while working on the engine preprocessor.
- lambdas: are sometimes useful as a convenience feature, but most of the times I just use function pointers.