Skip to content

Instantly share code, notes, and snippets.

@dk949
Last active April 19, 2025 03:13
Show Gist options
  • Save dk949/55ab7a19955b3161593067eb3837eb20 to your computer and use it in GitHub Desktop.
Save dk949/55ab7a19955b3161593067eb3837eb20 to your computer and use it in GitHub Desktop.
Provides a more convenient way to work with different kinds of dynamically polymorphic values
#ifndef UT_ASIS
#define UT_ASIS
#include <memory>
#include <type_traits>
namespace ut {
/**
* Try to downcast from reference type `From` to pointer to `To`.
*
* If cast cannot be performed, returns `nullptr`.
*
* Preserves constness.
*/
template<typename To, typename From>
auto as(From &&f) requires(
std::has_virtual_destructor_v<std::remove_reference_t<From>> &&std::is_base_of_v<std::remove_reference_t<From>, To>) {
using Ret = std::conditional_t<std::is_const_v<std::remove_reference_t<From>>, To const *, To *>;
return dynamic_cast<Ret>(&f);
}
/**
* Try to downcast from pointer type `From` to pointer to `To`.
*
* If cast cannot be performed, returns `nullptr`.
*
* Preserves constness.
*/
template<typename To, typename From>
auto as(From *f) requires(std::has_virtual_destructor_v<From> &&std::is_base_of_v<From, To>
) {
using Ret = std::conditional_t<std::is_const_v<From>, To const *, To *>;
return dynamic_cast<Ret>(f);
}
/**
* Try to downcast from `unique_ptr<From>` to pointer to `To`.
*
* If cast cannot be performed, returns `nullptr`.
*
* Preserves constness.
*/
template<typename To, typename From>
auto as(std::unique_ptr<From> const &f) requires(std::has_virtual_destructor_v<From> &&std::is_base_of_v<From, To>) {
using Ret = std::conditional_t<std::is_const_v<From>, To const *, To *>;
return dynamic_cast<Ret>(f.get());
}
/**
* Try to downcast from `shared_ptr<From>` to pointer to `To`.
*
* If cast cannot be performed, returns `nullptr`.
*
* Preserves constness.
*/
template<typename To, typename From>
auto as(std::shared_ptr<From> const &f) requires(std::has_virtual_destructor_v<From> &&std::is_base_of_v<From, To>) {
using Ret = std::conditional_t<std::is_const_v<From>, To const *, To *>;
return dynamic_cast<Ret>(f.get());
}
/**
* Checks if `From` has dynamic type `To`
*/
template<typename To, typename From>
bool is(From &&f) {
return !!as<To>(std::forward<From>(f));
}
} // namespace ut
#endif // UT_ASIS
Provides a more convenient way to work with different kinds of dynamically polymorphic values.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment