On Saturday, April 12, 2025, Henning Meyer wrote:

I would like to work generically with std::variant and std::any.



Not particularly relevant to this topic, but I think two or three years ago I wrote a class that is kind of halfway between 'variant' and 'any'. Basically you had all the benefits of 'any' except that it didn't dynamically allocate. So you had to specify a maximum size for the object, sort of like:

template<size_t N = 256zu>
class any_variant {
    constexpr std::size_t N = N;
    alignas(max_align_t) byte buf[N];
    type_info const *pti = nullptr;
    void (*destructor)(void*) noexcept = nullptr;
};

The best thing about it was that you got a compiler error (rather than a runtime error) if you tried to host an object that didn't fit, like this:

template<typename Tref>
constexpr any_variant &operator=(Tref &&arg) noexcept(noexcept(remove_cvref_t<Tref>(Tref&&)))
{
    static_assert( N >= sizeof arg );

    if ( destructor )
    {
        destructor(buf);  // better not throw
        destructor = nullptr;
        pti = nullptr;
    }

    typedef remove_cvref_t<Tref> T;

    construct_at<T>( (T*)buf, forward<Tref>(arg) );
    pti = &typeid(T);
    destructor = +[](void *const arg) noexcept
      {
          ((T*)arg)->~T();  // better not throw
      };
}

Might need compiler support to make it 'constexpr' because I cast a void* to a T*.