C++ Logo


Advanced search

Re: [std-proposals] [DRAFT PAPER] std::variant with std::specify_base

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Wed, 14 Sep 2022 22:57:13 +0100
On Wed, Sep 14, 2022 at 8:15 PM Lénárd Szolnoki via Std-Proposals
<std-proposals_at_[hidden]> wrote:

> There is no reason that variant<Cat, Dog> and variant<specify_base<Animal>, Cat, Dog> should be different types.

The former doesn't allow the variant object to have no object. The
second one is very similar to:

    variant< monostate, Cat, Dog >

In fact, it might make sense to define "specify_base" as follows:

    struct specify_base : monostate { . . . };

or perhaps even modify "monostate" so that instead of being simply:

    struct monostate { };

It would be:

    template<typename T = void>
    struct monostate { typedef T *base_ptr; };

and then specify_base could simply be:

    template<typename T>
    using specify_base = monostate<T>;

Just running through the options here, there's a dozen different ways
of doing this.

> At most this should be a facade over variant, with access to the underlying variant, when needed. But I prefer a convenience function over a variant even more.

I want it to be inside "std::variant" so that it can be used with
template functions and template classes like the following:

    template<typename... Types>
    void Print_Variant_Info(std::variant<Types...> const &v)
                std::cout << "Currently holding " << v.index() << std::endl;

> As for the implementation I believe there could be potential cv-correctness issues if varant holds cv-qualified alternatives.
> I believe variant<const Cat, Dog> is valid, you should not be able to get a non-const Animal pointer out of this.

I would use static_assert's to prevent the following:

    variant< specify_base<Animal>, Dog const, Cat >

But to allow the following:

    variant< specify_base<Animal const>, Dog const, Cat >

> Finally this whole thing feels a bit wrong for me.
> This is a weird mixture of two kinds of dynamic polymorphism when one would be enough.

Not sure what you mean here by "two kinds of dynamic polymorphism". If
you don't want use the 'new' operator or 'malloc', then you have three

(1) std::aligned_union (which is now deprecated)
(2) std::variant
(3) alignas(T) char buf[sizeof(T)]; T *const p = std::launder(buf +
0u); ::new(p) T; p->~T();

> In the end you pay for both kinds of dynamic dispatch, although hopefully the compiler can optimise the virtual call out.
> Even then, why pay both for a type discriminator plus a vtable pointer when you (hopefully) don't even use the vtable pointer?

If we don't know until runtime whether it will be a "JPEG_File" or a
"Bitmap_File" then of course the vtable pointer is used.

Received on 2022-09-14 21:57:26