I still don't understand why Frederick wants any changes to the existing std::variant. You can already do all of this today: given a `variant<Cat, Dog>`, it's trivial to get an `Animal*` out of it using `std::visit`. And you can even make your visitor return nullptr in the case that you're given a `variant<Cat, Dog, Tree>` where the active alternative happens to be `Tree`. Here's the code:

// https://godbolt.org/z/nbGda8h6K

template<class Base, class... Ts>
Base *specify_base(std::variant<Ts...>& v) {
return std::visit([](auto& t) -> Base* {
if constexpr (std::is_base_of_v<Base, std::decay_t<decltype(t)>>) {
return &t;
} else {
return nullptr;
}
}, v);
}

void test(std::variant<Cat, Dog, Tree> v) {
if (Animal *a = specify_base<Animal>(v)) {
a->speak();
} else {
std::cout << "trees don't speak\n";
}
}

On Thu, Sep 15, 2022 at 2:58 PM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Thu, Sep 15, 2022 at 9:33 PM Zhihao Yuan <zy@miator.net> wrote:
>
> I agree that variant<monostate, Cat, Dog>
> can be a model for
> variant<specify_base<Animal>, Cat, Dog>,
> but I also want variant<Cat, Dog> to
> implement an Animal interface.
> To summarize, I think
>
>   nonnull
>   nullable
>   throwing
>
> All make sense.
>
> How about this:
>
>   template<class T>
>   struct implements
>   {
>     template<class... Ts>
>     using model = std::variant<Ts...>;
>   };
>
>   template<class T>
>   struct implements_nullable
>   {
>     template<class... Ts>
>     using model = std::variant<std::monostate, Ts...>;
>
>     static auto default_proxy() noexcept { return nullptr; }
>   };
>
>   template<class T>
>   struct implements_or_throw
>   {
>     template<class... Ts>
>     using model = std::variant<std::monostate, Ts...>;
>   };


It isn't immediately apparent to me how you would use those. Something
like the following?

    implements<Animal>::model<Dog,Cat,Fish> obj;

    obj->Eat();

The whole point of my proposal is to have this simple syntax:
obj->BaseClassMethod();

I want it to all be inside "std::variant" so that the object can be
used in templates that expect an std::variant, and also so that the
"std::variant" object can be copied and it will still retain all of
its info (which wouldn't happen if we made a new class derived from
"std::variant").
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals