Samstag, 20. September 2014
Variants in C++ (ohne RTTI)
Manchmal ist es nötig, Variablen von verschiedenen Typen im gleichen Container zu speichern. Für diesen Zweck gibt es in vielen Programmiersprachen einen Variant-Typ - jedoch nicht in der C++ Standardbibliothek. Es gibt andere Implementierungen, aber die meisten haben den Fehler dass sie RTTI benötigen (und damit auch dort Kosten verursachen, wo sie gar nicht gebraucht werden). Viele haben obendrein eine umständliche Syntax, benutzen manchmal hässliche Makros und/oder sind vom Konzept her schwer verständlich. Dabei ist das völlig unnötig. Nach einigen eigenen mittelmäßig erfolgreichen Experimenten mit void*, CRTP und Lambdas bin ich schließlich bei einer fast schon lächerlich simplen Implementierung angekommen. Die Daten liegen auf dem Stack, der einzige Overhead ist der type_index, und lesen/schreiben ist komplett typensicher. Ein winziges Problem ist noch, dass manche Debugger den Datenzugriff bei Referenzen manchmal für einen Segfault halten (was er nicht ist; der Debugger kann das aber nicht wissen) - wenn man stattdessen (Smart-)Pointer benutzt, klappt alles wunderbar...

variant.hpp (hpp, 1 KB)

---

Variants in C++ (without RTTI)

Sometimes, you need to store variables of different types in the same container. That's what Variant types are for. But the C++ Standard Library doesn't have one. There are other implementations, of course - but most use RTTI, which creates overhead in places where the Variants aren't used or needed. Many also have a convoluted syntax, use ugly macros and/or are hard to grasp conceptually.
But it turns out that this is completely unnecessary. After some experiments using void*, CRTP and lambdas (with mixed results), I found an almost ridiculously simple way to do it. Everything is stored on the stack now, the only overhead is carrying the type_index around, and reading/writing is completely type safe.
There's still a minor problem though: Some debuggers may occasionally believe that accessing data on a Variant& is a segfault (which it is not, but there's no way for the debugger to know or check this). But if you're using (smart) pointers instead, there's no problem...

variant.hpp (hpp, 1 KB)

... link (0 Kommentare)   ... comment