boost::variant seems a powerful container to manipulate a heterogeneous set of types. I am wondering its cost. In memory, I think it takes up the size of the largest type plus an integer representing which(). For apply_visitor(), I think its performance is very good, it can call directly the function other than lots of ifs. Are my points right?
You're almost right.
The size of boost::variant
is is the max size of any element, rounded up as needed for the largest alignment, plus the size of some integer, and again rounded up.
Think about a variant of these types, assuming the tag is uint32_t
:
struct foo { uint32_t value[3]; }; // size 12, align 4
struct bar { uint64_t v2; }; // size 8, align 8
An untagged union must have size 16, align 8; adding the 4-byte tag must go up to size 24 to keep align 8.
Or consider a variant of:
struct foo { uint8_t value[5]; }; // size 5, align 1
struct bar { uint16_t v2; }; // size 2, align 2
An untagged union of these must have size 6, align 2; adding the 4-byte tag forces you to size 12, align 4.
For calling, I expect it uses an array-of-functions lookup (that's how I implemented my own variant, which was necessary since boost's didn't support move constructors), since if chains don't perform well and switches are impossible.
© 2022 - 2024 — McMap. All rights reserved.
apply_visitor
does "lots of ifs" under the hood (in fact it is more like a (big, metaprogrammed) switch on the kind (which()
) of the variant. Obviously, that's simply the minimum work required.) – Hohenlinden