C++ Logo

std-proposals

Advanced search

Re: [std-proposals] New method 'common_base' for 'std::variant'

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Fri, 9 Sep 2022 00:15:35 +0100
I have adapted Edward Catmur's code as follows:

#include <variant> // variant
#include <type_traits> // is_same_v, is_base_of_v

template<class... Types>
class my_variant : public std::variant<Types...> {
public:

    using std::variant<Types...>::variant; // Inherit constructors

private:

    template<class Base>
    static Base const volatile
*detail_common_base(std::variant<Types...> const volatile *const arg)
    {
        std::variant<Types...> *const p = const_cast<
std::variant<Types...> * >(arg);

        try
        {
            auto my_lambda = []<class U>(U &u) -> Base*
              {
                  if constexpr ( std::is_same_v<U, std::monostate> )
                  {
                      return nullptr;
                  }
                  else
                  {
                      static_assert( std::is_base_of_v<Base,U>,
                                     "Base class specified to
std::variant::common_base() "
                                     "is not a base class of currently
hosted object" );

                      return &u;
                  }
              };

            return std::visit<Base*>(my_lambda, *p);
        }
        catch (std::bad_variant_access const &)
        {
            return nullptr;
        }
    }

public:

    template<class Base>
    Base *common_base(void)
    {
        return const_cast<Base*>( detail_common_base<Base>(this) );
    }

    template<class Base>
    Base const *common_base(void) const
    {
        return const_cast<Base const *>( detail_common_base<Base>(this) );
    }

    template<class Base>
    Base volatile *common_base(void) volatile
    {
        return const_cast<Base volatile *>( detail_common_base<Base>(this) );
    }

    template<class Base>
    Base const volatile *common_base(void) const volatile
    {
        return const_cast<Base const volatile *>(
detail_common_base<Base>(this) );
    }
};

#include <iostream> // cout

struct Mammal { virtual void Speak(void) const volatile = 0; };
struct Dog : Mammal { void Speak(void) const volatile override {
std::cout << "Dog\n"; } };
struct Cat : Mammal { void Speak(void) const volatile override {
std::cout << "Cat\n"; } };

class Fish {};

my_variant<std::monostate,Dog,Cat> my_mammal;

int main(void)
{
    my_mammal.emplace<1u>();

    my_mammal.common_base<Mammal>()->Speak();

    // We can make a const volatile one too
    my_variant<std::monostate,Dog,Cat> const volatile my_cvmammal;

    // Mammal *p = some_other_object.common_base<Mammal>(); -- WON'T COMPILE
    Mammal const volatile *p = my_cvmammal.common_base<Mammal>();

    // If we add in a Fish, then we can no longer do common_base<Mammal>
    my_variant<std::monostate,Dog,Cat,Fish> volatile some_other_object;

    // Mammal volatile *const p =
some_other_object.common_base<Mammal>(); -- WON'T COMPILE
}


Note here that I wasn't able to use ".emplace<1u>()" on the volatile
object because std::variant doesn't have a 'volatile' form of the
'emplace' method!

Received on 2022-09-08 23:15:47