It is often quoted that C++s std::variant
has worse performance than variants in other languages. See e.g. https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html
One of the reasons is the exception
state, the other was said to be the requirement of the standard that std::visit
complexity does not depend on the number of types which forces implementers to use a dispatch table of function pointers which inhibits certain optimizations like inlining.
Questions:
- Would it be legal to implement
std::visit
as a chain ofif-elseif
where each check is likeif(v.index() == I) return visitor(get<I>(v));
? It seems like it does not because dispatching to higher indices would take more checks for the index. - Is it legal to implement it with a switch like
switch(v.index()) case I: return visitor(get<I>(v));
? This looks like "independent of the number of types" as control flow jumps directly to the case and it is how e.g. Microsoft implemented it for less than 64 (or so) types. - If the switch is legal, is it legal for the optimizer to convert small switches to if-elseif ladders? Again the MSVC compiler does this: https://godbolt.org/z/D2Q5ED. But IMO this violates the "independent of number of types" complexity mandated by the standard although it would in practice be faster.
I'm asking based on a discussion on reddit where someone claimed "Constant time" again refers to the behavior in the limit. which I don't really agree with. IMO "Constant time" means the time is constant no matter the input which for an if-elseif
-chain is not the case.
But I'm not sure how this applies here. It seems 1. is illegal, 2. is legal but the optimizer (may) transforms it into 1. which means that 2. is also illegal. At least if following the standard to the letter.