Add static_assert to upcasting constructor; add rcp_dynamic_cast()

This commit is contained in:
Josh Holtrop 2026-02-24 15:48:41 -05:00
parent ce921e31be
commit 7880adef89
2 changed files with 36 additions and 1 deletions

View File

@ -23,6 +23,7 @@
#pragma once
#include <atomic>
#include <type_traits>
/**
* Reference-counting pointer.
@ -97,10 +98,11 @@ public:
}
}
/* Casting constructor: allows rcp<Base> -> rcp<Derived> */
/* Upcasting constructor: allows rcp<Derived> -> rcp<Base> */
template <typename U>
rcp(const rcp<U> & other) : ptr(static_cast<T *>(other.get_raw()))
{
static_assert(std::is_base_of<T, U>::value, "rcp: implicit cast must be an upcast");
if (ptr)
{
ptr->rcp_inc();
@ -154,6 +156,12 @@ public:
}
};
template <typename T, typename U>
rcp<T> rcp_dynamic_cast(const rcp<U> & other)
{
return rcp<T>(dynamic_cast<T *>(other.get_raw()));
}
#define rcp_managed_root(classname) \
public: \
void rcp_inc() const \

View File

@ -181,6 +181,30 @@ void test_move_assignment_releases_existing()
assert(mybase_destruct == destructed_before + 2);
}
void test_upcast()
{
rcp<MyDerived> derived = MyDerived::create(1.5);
rcp<MyBase> base = derived;
assert(base);
assert(base->x == 1);
}
void test_dynamic_cast_success()
{
rcp<MyDerived> derived = MyDerived::create(1.5);
rcp<MyBase> base = derived;
rcp<MyDerived> back = rcp_dynamic_cast<MyDerived>(base);
assert(back);
assert(back->v == 1.5);
}
void test_dynamic_cast_failure()
{
rcp<MyBase> base = MyBase::create(1, 2);
rcp<MyDerived> derived = rcp_dynamic_cast<MyDerived>(base);
assert(!derived);
}
int main(int argc, char * argv[])
{
test_class_hierarchy();
@ -192,5 +216,8 @@ int main(int argc, char * argv[])
test_move_constructor();
test_move_assignment();
test_move_assignment_releases_existing();
test_upcast();
test_dynamic_cast_success();
test_dynamic_cast_failure();
return 0;
}