Closed cbeck88 closed 7 years ago
👍
@cbeck88 Will you add compilation time testing for your variant and others? Especially interested multivisitation. Take a look at my variant and benchmarks for it. There are perfect forwarding testing, multivisitation compile time benchmarking and others. https://github.com/tomilov/variant
The variant implementations you're mentioning are all making different design decisions especially for the controversial case when assignment throws an exception. This can be solved via backup copy (memory allocation), double buffering (inline dbackup copy, twice the size), or some sort of empty / valueless_by_exception state.
These all have different trade-off, and the last time I talked to @artemp about this mapbox/variant didn't care for exceptions during assignment at all.
@daniel-j-h: That's true, but I'm not measuring assignments, I'm only measuring speed of visitation. The main thing that affects it is what TMP strategy you use to convert the runtime-type info (the which()
value) back into a static value that you can use for dispatch. Most people did some tricks with an array of function pointers, I did something with a binary tree. mapbox::variant
just used naive tail recursion, and it turns out the compilers do the right thing with that. I guess if your variant has an empty state then you might potentially have to throw exceptions when visiting, so maybe that affects the speed of visitation. All these exception-advocates keep telling me that the overhead of that is minimal though :p
In regards to what happens when assignment throws an exception, what I do in my variant is basically, if the type is not no-throw move constructible, then it gets implicitly put in a recursive_wrapper
to make it no-throw move constructible. I didn't see that strategy in other variants but I think its a quite nice tradeoff, as I have no space wasted in the variant, no extra copies made of your objects, and I provide strong exception safety. Most programmers already are trying hard to make their objects no-throw move constructible since that puts them on the fast-track when used with std::vector
also.
Also, in regards to "not caring" for exceptions, they do a least set the enum to "invalid state" after destroying the contents. So, it's not strong exception safety, but it's what the C++17 std::variant
does also, iiuc
@tomilov : I guess that the only thing I'm benchmarking is speed of visitation right now, and what I learned from it is that naive tail-recursion is probably the best way. I can add your variant too though, it's pretty easy to do so.
I don't have anything set up to do compile-time benchmarks, and honestly I'm not too interested in that because my variant targets c++11 and afaik you can't really do a constexpr
variant until at least c++14.
@tomilov : It looks like I need to install a new libc++ to compile your variant, I don't want to do that right now, sorry.
closing for now
Hi, this is not a "problem" but rather I just wanted to cheer you guys on.
I have been working on my own variant type recently, and I decided to benchmark the visitation speed of variant types. Benchmark framework is pretty stable now, and
mapbox::variant
looks to be the fastest with both gcc and clang even for quite large numbers of types in the variant.You guys beat
boost::variant
,eggs::variant
,juice::variant
,std::experimental::variant
, libcxx devstd::variant
, and my variant, sometimes by a wide margin.Bench results here: https://github.com/cbeck88/strict-variant