3 ms·
No. There are 4-5 common approaches. - Macros, as you see. - Writing a generic implementation that takes a void* (or suitable "any" type). This has many, many
by yoklov 12y ago
No. There are 4-5 common approaches.
- Macros, as you see.
- Writing a generic implementation that takes a void* (or suitable "any" type). This has many, many drawbacks... no type safety, poor performance, frequently requires allocations if you want to store more than sizeof(void), forces the compiler to generate poor code...
- Custom data structures for your use-case. In my experience, this is the most common for performance-critical code. Doesn't end up being a problem nearly* as often as some people think (e.g., you don't spend much time writing data structure code), as you only write the subset for what you actually need at the time (A hash-table is fairly easy if you only need get-or-insert, exists, and clear), and you don't tend to need these data structures as much as you might think. This is still not ideal for some applications that require many containers (this is the minority of all applications, in my experience!).
- Intrusive containers. This only works in some cases (lists, trees, and chained hash tables), but basically the idea is that you put the shared part of the data structure as a struct at the front (or in the middle if the implementation does some offsetof math) of your type, and then all the operations use that. This tends to be less than ideal because of both the pointer chasing and storing additional pointers, but it beats the void* approach, and is better than poor implementations of the others, assuming you can do the data structure you want this way.
- Writing code that generates the code for the container for each type you need. This isn't as common as the other three but you definitely see it. Typically after generating it once it's customized but sometimes the ability to edit the generator and re-generate it might take priority.