diff --git a/src/small_unique_ptr.hpp b/src/small_unique_ptr.hpp index 3d1bab9..e4a1c00 100644 --- a/src/small_unique_ptr.hpp +++ b/src/small_unique_ptr.hpp @@ -206,6 +206,8 @@ namespace detail T* data_ = nullptr; }; + struct make_unique_small_impl; + } // namespace detail @@ -417,8 +419,7 @@ class small_unique_ptr : private detail::small_unique_ptr_base template friend class small_unique_ptr; - template - friend constexpr small_unique_ptr make_unique_small(Args&&...); + friend struct detail::make_unique_small_impl; }; template @@ -440,26 +441,41 @@ namespace std } // namespace std -template -[[nodiscard]] constexpr small_unique_ptr make_unique_small(Args&&... args) +namespace detail { - small_unique_ptr ptr; - - if (detail::is_always_heap_allocated_v || std::is_constant_evaluated()) - { - ptr.data_ = new T(std::forward(args)...); - } - else if constexpr (!detail::is_always_heap_allocated_v && std::is_polymorphic_v && !detail::has_virtual_move) - { - ptr.data_ = std::construct_at(ptr.buffer(), std::forward(args)...); - ptr.move_ = detail::move_buffer>; - } - else if constexpr (!detail::is_always_heap_allocated_v) + struct make_unique_small_impl { - ptr.data_ = std::construct_at(ptr.buffer(), std::forward(args)...); - } + template + static constexpr small_unique_ptr invoke(Args... args) + noexcept(std::is_nothrow_constructible_v && !detail::is_always_heap_allocated_v) + { + small_unique_ptr ptr; + + if (detail::is_always_heap_allocated_v || std::is_constant_evaluated()) + { + ptr.data_ = new T(std::forward(args)...); + } + else if constexpr (!detail::is_always_heap_allocated_v && std::is_polymorphic_v && !detail::has_virtual_move) + { + ptr.data_ = std::construct_at(ptr.buffer(), std::forward(args)...); + ptr.move_ = detail::move_buffer>; + } + else if constexpr (!detail::is_always_heap_allocated_v) + { + ptr.data_ = std::construct_at(ptr.buffer(), std::forward(args)...); + } + + return ptr; + } + }; - return ptr; +} // namespace detail + +template +[[nodiscard]] constexpr small_unique_ptr make_unique_small(Args&&... args) +noexcept(std::is_nothrow_constructible_v && !detail::is_always_heap_allocated_v) +{ + return detail::make_unique_small_impl::invoke(std::forward(args)...); } #endif // !SMALL_UNIQUE_PTR_HPP diff --git a/test/small_unique_ptr.cpp b/test/small_unique_ptr.cpp index 4aff134..5d91982 100644 --- a/test/small_unique_ptr.cpp +++ b/test/small_unique_ptr.cpp @@ -96,6 +96,12 @@ TEST_CASE("construction", "[small_unique_ptr]") REQUIRE_NOTHROW(make_unique_small()); } +TEST_CASE("noexcept_construction", "[small_unique_ptr]") +{ + STATIC_REQUIRE(noexcept(make_unique_small())); + STATIC_REQUIRE(!noexcept(make_unique_small())); +} + TEST_CASE("is_always_heap_allocated", "[small_unique_ptr]") { STATIC_REQUIRE(!small_unique_ptr::is_always_heap_allocated());