Variants of 680 Types
13 May 2020Richard Hodges asked me whether Variant2 supports 680 types.
You might be tempted to respond to that with “why would any sane person need a variant of 680 types??”, but we here at Variant2 Enterprises, LLC ask our customers no such questions, particularly not using more than one question mark in the process.
The answer turned out to be a qualified “yes”, the qualification being a fast machine with 128GB RAM.
I had never tried putting as many types into variant2::variant
, just kind
of assumed that it would of course work. It turned out to hit two problems.
First, due to the way std::variant
is specified to support constexpr
operations, a specification which variant2
follows, the necessary underlying
structure is a recursive union, something like
template<class T1, class... T> union storage
{
T1 first_;
storage<T...> rest_;
};
This meant that 680 types caused 680 template instantiations of this
storage
type. Template instantiations are expensive, both in time and
in space. Compiler Explorer’s time limit (and memory quota) were
being exceeded for 200 types, let alone
680.
I added a specialization that cut down the storage instantiations by a factor of 10, which enabled the above example to compile on CE.
The second problem was the implementation of
mp11::mp_with_index
,
which powers variant2::visit
. It generates a switch of however many
alternatives are requested (680 in our case), but did so 16 alternatives
at a time, which meant 40+ switch statements. This, again for 200 types, often
exceeded the ability of CE’s version of g++.
I changed
mp_with_index
to divide the alternatives in half, and it
conquered.
So now you no longer need 128GB RAM to use variants of 680 types, although they still don’t set any compilation speed records.