#pragma once #include "PreConfig.hpp" #include #include namespace cru { template class SelfResolvable; template class ObjectResolver { friend SelfResolvable; private: ObjectResolver(const std::shared_ptr& resolver) : resolver_(resolver) {} public: ObjectResolver(const ObjectResolver&) = default; ObjectResolver& operator=(const ObjectResolver&) = default; ObjectResolver(ObjectResolver&&) = default; ObjectResolver& operator=(ObjectResolver&&) = default; ~ObjectResolver() = default; T* Resolve() const { // resolver_ is null only when this has been moved. // You shouldn't resolve a moved resolver. So assert it. Expects(resolver_); return *resolver_; } private: std::shared_ptr resolver_; }; template class SelfResolvable { public: SelfResolvable() : resolver_(new T*(static_cast(this))) {} SelfResolvable(const SelfResolvable&) = delete; SelfResolvable& operator=(const SelfResolvable&) = delete; // Resolvers to old object will resolve to new object. SelfResolvable(SelfResolvable&& other) : resolver_(std::move(other.resolver_)) { (*resolver_) = static_cast(this); } // Old resolvers for this object will resolve to nullptr. // Other's resolvers will now resolve to this. SelfResolvable& operator=(SelfResolvable&& other) { if (this != &other) { (*resolver_) = nullptr; resolver_ = std::move(other.resolver_); (*resolver_) = static_cast(this); } return *this; } virtual ~SelfResolvable() { if (resolver_ != nullptr) (*resolver_) = nullptr; } ObjectResolver CreateResolver() { return ObjectResolver(resolver_); } private: std::shared_ptr resolver_; }; } // namespace cru