diff --git a/include/gsl/pointers b/include/gsl/pointers index 0389b76..c36999b 100644 --- a/include/gsl/pointers +++ b/include/gsl/pointers @@ -68,10 +68,9 @@ using owner = T; template class not_null { -public: - static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); - template ::value>> +public: + template ::value>::type> constexpr not_null(U&& u) : ptr_(std::forward(u)) { Expects(ptr_ != nullptr); @@ -86,7 +85,8 @@ public: not_null(const not_null& other) = default; not_null& operator=(const not_null& other) = default; - constexpr T get() const + + constexpr T const & get() const { /* not_null constructors and assignment operators always verify ptr_ is @@ -97,8 +97,8 @@ public: return ptr_; } - constexpr operator T() const { return get(); } - constexpr T operator->() const { return get(); } + constexpr operator T const & () const { return get(); } + constexpr T const & operator->() const { return get(); } constexpr decltype(auto) operator*() const { return *get(); } // prevents compilation when someone attempts to assign a null pointer constant diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index a7ef27e..3d53d31 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -56,6 +56,7 @@ struct CustomPtr { CustomPtr(T* p) : p_(p) {} operator T*() { return p_; } + operator T*() const { return p_; } bool operator!=(std::nullptr_t) const { return p_ != nullptr; } T* p_ = nullptr; }; @@ -329,3 +330,47 @@ TEST_CASE("TestNotNullCustomPtrComparison") } static_assert(std::is_nothrow_move_constructible>::value, "not_null must be no-throw move constructible"); + +struct UniquePointerTestStruct { + int i = 0; +}; + +TEST_CASE("TestNotNullUniquePtrComparison") { + + { + using NotNull1 = not_null>; + + // values are the same + CHECK((*NotNull1(std::make_unique(42)) == *NotNull1(std::make_unique(42)))); + } + { + using NotNull1 = not_null>; + + // values are the same + CHECK((NotNull1(std::make_unique())->i == NotNull1(std::make_unique())->i)); + } +} + + +template +struct UncopyableUnmovablePointerLikeType { +private: + T * t; + +public: + UncopyableUnmovablePointerLikeType(T * pointer) : t(pointer) {} + UncopyableUnmovablePointerLikeType(const UncopyableUnmovablePointerLikeType&) = delete; + UncopyableUnmovablePointerLikeType(UncopyableUnmovablePointerLikeType &&) = delete; + + operator T*() { return t; } + operator T*() const { return t; } +}; + + +// this test case makes sure not_null works on move-only types like std::unique_ptr as well as verifying +// that no copy penalty is being paid for types with expensive copy constructors like std::shared_ptr +TEST_CASE("ConfirmCopyableAndMoveablePointerTypeNotRequired") { + int i = 5; + gsl::not_null> fixed_in_place(&i); + CHECK(*fixed_in_place == 5); +}