@@ -115,10 +115,20 @@ class observable_unique_ptr_base {
115115 }
116116
117117 // / Fill in the observer pointer for objects inheriting from enable_observer_from_this.
118- void set_this_observer_ () noexcept {
119- if constexpr (std::is_base_of_v<details::enable_observer_from_this_base, T>) {
120- if (ptr_deleter.data ) {
121- ptr_deleter.data ->this_observer .set_data_ (block, ptr_deleter.data );
118+ /* * \note It is important to preserve the type of the pointer as supplied by the user.
119+ * It might be of a derived type that inherits from enable_observer_from_this, while
120+ * the base type T might not. We still want to fill in the observer pointer if we can.
121+ */
122+ template <typename U>
123+ void set_this_observer_ (U* p) noexcept {
124+ if constexpr (std::is_convertible_v<U*,const details::enable_observer_from_this_base*>) {
125+ using input_observer_type = std::decay_t <decltype (p->this_observer )>;
126+ using observer_element_type = typename input_observer_type::element_type;
127+ static_assert (std::is_convertible_v<U*, observer_element_type*>,
128+ " incompatible type specified in enable_observer_from_this" );
129+
130+ if (p) {
131+ p->this_observer .set_data_ (block, p);
122132 ++block->refcount ;
123133 }
124134 }
@@ -440,9 +450,10 @@ class observable_unique_ptr :
440450 * observable_unique_ptr is created. If possible, prefer
441451 * using make_observable_unique() instead of this constructor.
442452 */
443- explicit observable_unique_ptr (T* value) :
453+ template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*,T*>>>
454+ explicit observable_unique_ptr (U* value) :
444455 base(value != nullptr ? allocate_block_() : nullptr, value) {
445- base::set_this_observer_ ();
456+ base::set_this_observer_ (value );
446457 }
447458
448459 // / Explicit ownership capture of a raw pointer, with customer deleter.
@@ -452,9 +463,10 @@ class observable_unique_ptr :
452463 * observable_unique_ptr is created. If possible, prefer
453464 * using make_observable_unique() instead of this constructor.
454465 */
455- explicit observable_unique_ptr (T* value, Deleter del) :
466+ template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*,T*>>>
467+ explicit observable_unique_ptr (U* value, Deleter del) :
456468 base(value != nullptr ? allocate_block_() : nullptr, value, std::move(del)) {
457- base::set_this_observer_ ();
469+ base::set_this_observer_ (value );
458470 }
459471
460472 // / Transfer ownership by implicit casting
@@ -484,10 +496,11 @@ class observable_unique_ptr :
484496 * pointer is set to null and looses ownership. The deleter
485497 * is default constructed.
486498 */
487- template <typename U, typename D>
488- observable_unique_ptr (observable_unique_ptr<U,D>&& manager, T* value) noexcept :
499+ template <typename U, typename D, typename V, typename enable =
500+ std::enable_if_t <std::is_convertible_v<V*,T*>>>
501+ observable_unique_ptr (observable_unique_ptr<U,D>&& manager, V* value) noexcept :
489502 base (std::move(manager), value) {
490- base::set_this_observer_ ();
503+ base::set_this_observer_ (value );
491504 }
492505
493506 // / Transfer ownership by explicit casting
@@ -497,10 +510,11 @@ class observable_unique_ptr :
497510 * \note After this observable_unique_ptr is created, the source
498511 * pointer is set to null and looses ownership.
499512 */
500- template <typename U, typename D>
501- observable_unique_ptr (observable_unique_ptr<U,D>&& manager, T* value, Deleter del) noexcept :
513+ template <typename U, typename D, typename V, typename enable =
514+ std::enable_if_t <std::is_convertible_v<V*,T*>>>
515+ observable_unique_ptr (observable_unique_ptr<U,D>&& manager, V* value, Deleter del) noexcept :
502516 base (std::move(manager), value, del) {
503- base::set_this_observer_ ();
517+ base::set_this_observer_ (value );
504518 }
505519
506520 // / Transfer ownership by implicit casting
@@ -548,7 +562,8 @@ class observable_unique_ptr :
548562 // / Replaces the managed object.
549563 /* * \param ptr A nullptr_t instance
550564 */
551- void reset (T* ptr) noexcept {
565+ template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*,T*>>>
566+ void reset (U* ptr) noexcept {
552567 // Copy old pointer
553568 T* old_ptr = base::ptr_deleter.data ;
554569 control_block_type* old_block = base::block;
@@ -563,7 +578,7 @@ class observable_unique_ptr :
563578 base::delete_and_pop_ref_ (old_block, old_ptr, base::ptr_deleter);
564579 }
565580
566- base::set_this_observer_ ();
581+ base::set_this_observer_ (ptr );
567582 }
568583
569584 // / Releases ownership of the managed object and mark observers as expired.
@@ -625,9 +640,10 @@ class observable_sealed_ptr :
625640 * \param value The pointer to own
626641 * \note This is used by make_observable_sealed().
627642 */
628- observable_sealed_ptr (control_block_type* ctrl, T* value) noexcept :
643+ template <typename U, typename enable = std::enable_if_t <std::is_convertible_v<U*,T*>>>
644+ observable_sealed_ptr (control_block_type* ctrl, U* value) noexcept :
629645 base (ctrl, value, oup::placement_delete<T>{}) {
630- base::set_this_observer_ ();
646+ base::set_this_observer_ (value );
631647 }
632648
633649 // Friendship is required for conversions.
@@ -659,7 +675,8 @@ class observable_sealed_ptr :
659675 // / Explicit ownership capture of a raw pointer is forbidden.
660676 /* * \note If you need to do this, use observable_unique_ptr instead.
661677 */
662- explicit observable_sealed_ptr (T*) = delete;
678+ template <typename U>
679+ explicit observable_sealed_ptr (U*) = delete;
663680
664681 // / Transfer ownership by implicit casting
665682 /* * \param value The pointer to take ownership from
@@ -760,6 +777,7 @@ observable_unique_ptr<T> make_observable_unique(Args&& ... args) {
760777template <typename T, typename ... Args>
761778observable_sealed_ptr<T> make_observable_sealed (Args&& ... args) {
762779 using block_type = typename observable_sealed_ptr<T>::control_block_type;
780+ using decayed_type = std::decay_t <T>;
763781
764782 // Allocate memory
765783 constexpr std::size_t block_size = sizeof (block_type);
@@ -769,7 +787,7 @@ observable_sealed_ptr<T> make_observable_sealed(Args&& ... args) {
769787 try {
770788 // Construct control block and object
771789 block_type* block = new (buffer) block_type;
772- T * ptr = new (buffer + block_size) T (std::forward<Args>(args)...);
790+ decayed_type * ptr = new (buffer + block_size) decayed_type (std::forward<Args>(args)...);
773791
774792 // Make owner pointer
775793 return observable_sealed_ptr<T>(block, ptr);
@@ -1184,6 +1202,15 @@ bool operator!= (const observer_ptr<T>& first, const observer_ptr<U>& second) no
11841202* calling observer_from_this(). If the latter condition is not satisfied,
11851203* i.e., the object was allocated on the stack, or is owned by another
11861204* type of smart pointer, then observer_from_this() will return nullptr.
1205+ *
1206+ * **Corner cases.**
1207+ * - If a class A inherits from both another class B and enable_observer_from_this<A>,
1208+ * and it is owned by an observable_unique_ptr<B>. The function observer_from_this()
1209+ * will always return nullptr if ownership is taken from a pointer to B*, but will
1210+ * be a valid pointer if ownership is taken from a pointer to A*.
1211+ *
1212+ * observable_unique_ptr<B> p(new A); // observer pointer is valid
1213+ * observable_unique_ptr<B> p(static_cast<B*>(new A)); // observer pointer is nullptr
11871214*/
11881215template <typename T>
11891216class enable_observer_from_this : public details ::enable_observer_from_this_base {
0 commit comments