For std::any and std::variant we have functions to request the object about current contained value, that return nullptr if the request cannot be satisfied (just like dynamic_cast does):
template<class ValueType>
const ValueType *any_cast(const any *operand);
template<class ValueType>
ValueType *any_cast(any *operand);
and
template <class T, class... Types>
std::add_pointer_t<T> get_if(variant<Types...> *pv);
template <class T, class... Types>
std::add_pointer_t<const T> get_if(const variant<Types...> *pv);
Both take pointer as an argument. Why? It is not efficient. The implementation has every time to check if the argument is not nullptr. Does nullptr argument makes any sense at all?
This functions can be class members or take a reference as an argument (may be with slightly different names). What are reasons for suboptimal design like this? Just mimic dynamic_cast interface?