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!
#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