// Copyright (c) 2018-2025 Jean-Louis Leroy // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt // or q at http://www.boost.org/LICENSE_1_0.txt) #include #include #define BOOST_TEST_MODULE openmethod #include #include #include "test_virtual_ptr_value_semantics.hpp" #include #ifdef BOOST_GCC #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif #ifdef __clang__ #pragma clang diagnostic ignored "-Wunused-local-typedefs" #endif struct using_shared_ptr { template using ptr = std::shared_ptr; template using virtual_ptr = shared_virtual_ptr; template static decltype(auto) make(Args&&... args) { return std::make_shared(std::forward(args)...); } template static decltype(auto) make_virtual(Args&&... args) { return make_shared_virtual(std::forward(args)...); } static bool cast_moves() { initialize(); ptr animal = make(); (void)std::static_pointer_cast(animal); return animal.get() == nullptr; } }; struct using_boost_intrusive_ptr { template using ptr = boost::intrusive_ptr; template using virtual_ptr = boost_intrusive_virtual_ptr; template static auto make(Args&&... args) { return boost::intrusive_ptr( new Class(std::forward(args)...)); } template static auto make_virtual(Args&&... args) { return make_boost_intrusive_virtual(std::forward(args)...); } static bool cast_moves() { return false; } }; using smart_pointers = boost::mp11::mp_list; #define USING_DECLARATIONS \ using animal_ptr = typename smart::template ptr; \ using const_animal_ptr = typename smart::template ptr; \ using animal_virtual_ptr = typename smart::template virtual_ptr; \ using const_animal_virtual_ptr = \ typename smart::template virtual_ptr; \ using dog_ptr = typename smart::template ptr; \ using const_dog_ptr = typename smart::template ptr; \ using dog_virtual_ptr = typename smart::template virtual_ptr; \ using const_dog_virtual_ptr = \ typename smart::template virtual_ptr; \ using cat_ptr = typename smart::template ptr; \ using const_cat_ptr = typename smart::template ptr; \ using cat_virtual_ptr = typename smart::template virtual_ptr; \ using const_cat_virtual_ptr = \ typename smart::template virtual_ptr; BOOST_AUTO_TEST_CASE_TEMPLATE( smart_pointer_value_semantics, smart, smart_pointers) { USING_DECLARATIONS; static_assert(SameSmartPtr); static_assert( !SameSmartPtr, default_registry>); static_assert( std::is_same_v); static_assert(std::is_same_v< decltype(std::declval().get()), Animal*>); static_assert(IsSmartPtr); static_assert(IsSmartPtr); static_assert( std::is_same_v()), Animal&>); initialize(); // construction and assignment from a plain pointer or reference is not // allowed static_assert(!construct_assign_ok); static_assert(!construct_assign_ok); static_assert(!construct_assign_ok); static_assert(!construct_assign_ok); // ------------------------------------------------------------------------- // construction and assignment from plain references and pointers { dog_virtual_ptr p{nullptr}; BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } { auto snoopy = smart::template make(); dog_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); p = *&p; BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto hector = smart::template make(); p = hector; BOOST_TEST(p.get() == hector.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); animal_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto felix = smart::template make(); p = felix; BOOST_TEST(p.get() == felix.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); const_dog_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto hector = smart::template make(); p = hector; BOOST_TEST(p.get() == hector.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { const auto snoopy = smart::template make(); const_animal_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto felix = smart::template make(); p = felix; BOOST_TEST(p.get() == felix.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); dog_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto hector = smart::template make(); p = hector; BOOST_TEST(p.get() == hector.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); animal_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto felix = smart::template make(); p = felix; BOOST_TEST(p.get() == felix.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); const_dog_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto hector = smart::template make(); p = hector; BOOST_TEST(p.get() == hector.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto snoopy = smart::template make(); const_animal_virtual_ptr p(snoopy); BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); auto felix = smart::template make(); p = felix; BOOST_TEST(p.get() == felix.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } // dog_virtual_ptr p{Dog()}; static_assert(!construct_assign_ok); // ------------------------------------------------------------------------- // construction and assignment from other shared_virtual_ptr { // dog_virtual_ptr(const dog_virtual_ptr&) auto snoopy = smart::template make(); const dog_virtual_ptr p(snoopy); dog_virtual_ptr q(p); BOOST_TEST(q.get() == snoopy.get()); BOOST_TEST(q.vptr() == default_registry::template static_vptr); } { // dog_virtual_ptr(dog_virtual_ptr&) auto snoopy = smart::template make(); dog_virtual_ptr p(snoopy); dog_virtual_ptr q(p); BOOST_TEST(q.get() == snoopy.get()); BOOST_TEST(q.vptr() == default_registry::template static_vptr); } { // dog_virtual_ptr(dog_virtual_ptr&&) auto snoopy = smart::template make(); dog_virtual_ptr p(snoopy); dog_virtual_ptr q(std::move(p)); BOOST_TEST(q.get() == snoopy.get()); BOOST_TEST(q.vptr() == default_registry::template static_vptr); BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } { // animal_virtual_ptr(const dog_virtual_ptr&) auto snoopy = smart::template make(); const dog_virtual_ptr p(snoopy); animal_virtual_ptr base(p); BOOST_TEST(base.get() == snoopy.get()); BOOST_TEST(base.vptr() == default_registry::template static_vptr); } { // shared_virtual_ptr(const dog_virtual_ptr&) auto snoopy = smart::template make(); const dog_virtual_ptr p(snoopy); const_dog_virtual_ptr const_q(p); BOOST_TEST(const_q.get() == snoopy.get()); BOOST_TEST( const_q.vptr() == default_registry::template static_vptr); } { // shared_virtual_ptr(const dog_virtual_ptr&) auto snoopy = smart::template make(); const dog_virtual_ptr p(snoopy); const_animal_virtual_ptr const_base_q(p); BOOST_TEST(const_base_q.get() == snoopy.get()); BOOST_TEST( const_base_q.vptr() == default_registry::template static_vptr); } { // dog_virtual_ptr() dog_virtual_ptr p{nullptr}; BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } { dog_virtual_ptr p{dog_ptr()}; BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } // ------------------------------------------------------------------------- // assignment { dog_virtual_ptr p; auto snoopy = smart::template make(); p = snoopy; BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { dog_virtual_ptr p; auto snoopy = smart::template make(); p = snoopy; BOOST_TEST(p.get() == snoopy.get()); BOOST_TEST(p.vptr() == default_registry::template static_vptr); } { auto p = smart::template make_virtual(); p = nullptr; BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } { auto p = smart::template make_virtual(); p = dog_ptr(); BOOST_TEST(p.get() == nullptr); BOOST_TEST(p.vptr() == nullptr); } static_assert(!construct_assign_ok); static_assert(!construct_assign_ok); } BOOST_AUTO_TEST_CASE_TEMPLATE(cast_smart_pointer_value, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_ptr animal = smart::template make(); dog_ptr dog = virtual_traits::template cast( animal); BOOST_TEST(dog.get() == animal.get()); } BOOST_AUTO_TEST_CASE_TEMPLATE( cast_smart_ptr_lvalue_reference, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_ptr animal = smart::template make(); dog_ptr dog = virtual_traits::template cast< const dog_ptr&>(animal); BOOST_TEST(dog.get() == animal.get()); dog_ptr dog2 = virtual_traits< const dog_ptr&, default_registry>::template cast(dog); BOOST_TEST(dog2.get() == dog.get()); } BOOST_AUTO_TEST_CASE_TEMPLATE( cast_smart_ptr_xvalue_reference, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_ptr animal = smart::template make(); auto p = animal.get(); auto dog = virtual_traits::template cast( std::move(animal)); BOOST_TEST(dog.get() == p); if (smart::cast_moves()) { BOOST_TEST(animal.get() == nullptr); } } BOOST_AUTO_TEST_CASE_TEMPLATE( cast_shared_virtual_ptr_value, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_virtual_ptr base = smart::template make(); auto derived = virtual_traits< animal_virtual_ptr, default_registry>::template cast(base); BOOST_TEST(derived.get() == base.get()); BOOST_TEST(base.vptr() == default_registry::static_vptr); BOOST_TEST(derived.vptr() == default_registry::static_vptr); } BOOST_AUTO_TEST_CASE_TEMPLATE( cast_shared_virtual_ptr_lvalue_reference, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_virtual_ptr base = smart::template make(); auto derived = virtual_traits:: template cast(base); BOOST_TEST(derived.get() == base.get()); BOOST_TEST(base.vptr() == default_registry::static_vptr); BOOST_TEST(derived.vptr() == default_registry::static_vptr); } BOOST_AUTO_TEST_CASE_TEMPLATE( cast_shared_virtual_ptr_xvalue_reference, smart, smart_pointers) { USING_DECLARATIONS; initialize(); animal_virtual_ptr base = smart::template make(); auto p = base.get(); auto derived = virtual_traits::template cast< dog_virtual_ptr>(std::move(base)); BOOST_TEST(derived.get() == p); BOOST_TEST(derived.vptr() == default_registry::static_vptr); if (smart::cast_moves()) { BOOST_TEST(base.get() == nullptr); } } template struct check_illegal_smart_ops< std::shared_ptr, std::unique_ptr, direct_vector>; template struct check_illegal_smart_ops< boost::intrusive_ptr, std::unique_ptr, direct_vector>;