c++templatesc++11boost-mplboost-variant

Determining largest sizeof() in boost variant


Given:

boost::variant<T1,T2,T3,...,TN>

Calculate the following at compile time:

max(sizeof(T1), sizeof(T2), sizeof(T3),... ,sizeof(TN))

I had no idea how to approach this, but this answer shed some light on how I might get started. Using the code in that answer with two types, T1 and T2, I could use the following in a source file to get the size of the larger object:

size_t largestSize = sizeof(largest<T1, T2>::type);

This is exactly what I'd like to do, but I need the largest template to work with more than two classes - specifically, it would need to check all types stored in a boost::variant object.

I know that boost::variant has a types typedef, which defines some sort of list of types in the variant. The problem is, I get totally lost when I try to wrap my head around all the boost::mpl stuff in the implementation. I don't intuitively understand what boost::variant::types is, and how I might be able to pass it into my own template that does something with it.

In my head, this is what the final implementation might look like:

typedef boost::variant<T1, T2, T3, T4> MyVariant;
size_t largestSize = sizeof(largest<MyVariant::types>::type);

Unfortunately, I have no idea how to go about implementing this version of largest.

I'm not sure if this is a reasonable approach, so I'm open to any other ways to accomplish this (maybe apply a boost::static_visitor to all types at compile time?).


Solution

  • Just ignore the mpl stuff. Start with:

    template <class T> struct max_variant_sizeof;
    
    template <class... Ts>
    struct max_variant_sizeof<boost::variant<Ts...>> {
        static constexpr size_t value = variadic_max(sizeof(Ts)...);
    };
    

    Now max_variant_sizeof<MyVariant>::value will forward all the sizes of all the types to a function. All you need to do is write that variadic_max:

    constexpr size_t variadic_max(size_t v) { return v; }
    
    template <class... Args>
    constexpr size_t variadic_max(size_t a, size_t b, Args... cs)
    {
        return variadic_max(std::max(a, b), cs...);
    }
    

    Before C++14, std::max() isn't constexpr, so that can be replaced with:

        return variadic_max((a > b ? a : b), cs...);
    

    One thing worth noting about:

    maybe apply a boost::static_visitor to all types at compile time?

    Visitation with a variant is a runtime operation - your visitor gets called with the type that the variant happens to be holding on to. It will not be called with all the types.