diff --git a/include/gsl.h b/include/gsl.h index fed3b6c..bf3573e 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -111,21 +111,27 @@ class not_null static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); public: not_null(T t) : ptr_(t) { ensure_invariant(); } - - // deleting these two prevents compilation when initialized with a nullptr or literal 0 - not_null(std::nullptr_t) = delete; - not_null(int) = delete; + not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; } not_null(const not_null &other) = default; + not_null& operator=(const not_null &other) = default; template ::value>> - not_null(const not_null &other) : ptr_(other.get()) + not_null(const not_null &other) { + *this = other; } - not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; } + template ::value>> + not_null& operator=(const not_null &other) + { + ptr_ = other.get(); + return *this; + } // prevents compilation when someone attempts to assign a nullptr + not_null(std::nullptr_t) = delete; + not_null(int) = delete; not_null& operator=(std::nullptr_t) = delete; not_null& operator=(int) = delete; @@ -166,26 +172,18 @@ private: // // Describes an optional pointer - provides symmetry with not_null // +template +class maybe_null_ret; + template class maybe_null_dbg { static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); public: maybe_null_dbg() : ptr_(nullptr), tested_(false) {} + maybe_null_dbg(std::nullptr_t) : ptr_(nullptr), tested_(false) {} maybe_null_dbg(const T& p) : ptr_(p), tested_(false) {} - maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {} - - template ::value>> - maybe_null_dbg(const not_null &other) : ptr_(other.get()), tested_(false) - { - } - - template ::value>> - maybe_null_dbg(const maybe_null_dbg &other) : ptr_(other.get()), tested_(false) - { - } - maybe_null_dbg& operator=(const T& p) { if (ptr_ != p) @@ -196,6 +194,8 @@ public: return *this; } + + maybe_null_dbg(const maybe_null_dbg& rhs) : ptr_(rhs.ptr_), tested_(false) {} maybe_null_dbg& operator=(const maybe_null_dbg& rhs) { if (this != &rhs) @@ -206,6 +206,43 @@ public: return *this; } + + template ::value>> + maybe_null_dbg(const not_null &other) : ptr_(other.get()), tested_(false) {} + + template ::value>> + maybe_null_dbg& operator=(const not_null &other) + { + ptr_ = other.get(); + tested_ = false; + return *this; + } + + + template ::value>> + maybe_null_dbg(const maybe_null_dbg &other) : ptr_(other.get()), tested_(false) {} + + template ::value>> + maybe_null_dbg& operator=(const maybe_null_dbg &other) + { + ptr_ = other.get(); + tested_ = false; + return *this; + } + + + template ::value>> + maybe_null_dbg(const maybe_null_ret &other) : ptr_(other.get()), tested_(false) {} + + template ::value>> + maybe_null_dbg& operator=(const maybe_null_ret &other) + { + ptr_ = other.get(); + tested_ = false; + return *this; + } + + bool present() const { tested_ = true; return ptr_ != nullptr; } bool operator==(const T& rhs) const { tested_ = true; return ptr_ == rhs; } @@ -225,8 +262,6 @@ public: T operator->() const { return get(); } private: - const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type - // unwanted operators...pointers only point to single objects! // TODO ensure all arithmetic ops on this type are unavailable maybe_null_dbg& operator++() = delete; @@ -249,27 +284,46 @@ class maybe_null_ret public: maybe_null_ret() : ptr_(nullptr) {} maybe_null_ret(std::nullptr_t) : ptr_(nullptr) {} + maybe_null_ret(const T& p) : ptr_(p) {} + maybe_null_ret& operator=(const T& p) { ptr_ = p; return *this; } + maybe_null_ret(const maybe_null_ret& rhs) = default; - - template ::value>> - maybe_null_ret(const not_null &other) : ptr_(other.get()) - { - } - - template ::value>> - maybe_null_ret(const maybe_null_ret &other) : ptr_(other.get()) - { - } - - template ::value>> - maybe_null_ret(const maybe_null_dbg &other) : ptr_(other.get()) - { - } - - maybe_null_ret& operator=(const T& p) { if (ptr_ != p) { ptr_ = p; } return *this; } maybe_null_ret& operator=(const maybe_null_ret& rhs) = default; + template ::value>> + maybe_null_ret(const not_null &other) : ptr_(other.get()) {} + + template ::value>> + maybe_null_ret& operator=(const not_null &other) + { + ptr_ = other.get(); + return *this; + } + + + template ::value>> + maybe_null_ret(const maybe_null_ret &other) : ptr_(other.get()) {} + + template ::value>> + maybe_null_ret& operator=(const maybe_null_ret &other) + { + ptr_ = other.get(); + return *this; + } + + + template ::value>> + maybe_null_ret(const maybe_null_dbg &other) : ptr_(other.get()) {} + + template ::value>> + maybe_null_ret& operator=(const maybe_null_dbg &other) + { + ptr_ = other.get(); + return *this; + } + + bool present() const { return ptr_ != nullptr; } T get() const { return ptr_; } @@ -289,7 +343,6 @@ private: maybe_null_ret& operator-(size_t) = delete; maybe_null_ret& operator-=(size_t) = delete; - const size_t ptee_size_ = sizeof(*ptr_); // T must be a pointer type T ptr_; }; diff --git a/tests/maybenull_tests.cpp b/tests/maybenull_tests.cpp index 4b74114..d6b53f0 100644 --- a/tests/maybenull_tests.cpp +++ b/tests/maybenull_tests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Guide; @@ -254,6 +255,43 @@ SUITE(MaybeNullTests) // Make sure we no longer throw here CHECK(p1.get() != nullptr); } + + TEST(TestMaybeNullAssignmentOps) + { + MyBase base; + MyDerived derived; + Unrelated unrelated; + + not_null nnBase(&base); + not_null nnDerived(&derived); + not_null nnUnrelated(&unrelated); + + maybe_null_ret mnBase_ret1(&base), mnBase_ret2; + mnBase_ret2 = mnBase_ret1; // maybe_null_ret = maybe_null_ret + mnBase_ret2 = nnBase; // maybe_null_ret = not_null + + maybe_null_ret mnDerived_ret(&derived); + mnBase_ret2 = mnDerived_ret; // maybe_null_ret = maybe_null_ret + mnBase_ret1 = &derived; // maybe_null_ret = U; + mnBase_ret1 = nnDerived; // maybe_null_ret = not_null + + maybe_null_ret mnUnrelated_ret; + mnUnrelated_ret = &unrelated; // maybe_null_ret = T + + maybe_null_dbg mnBase_dbg1(&base), mnBase_dbg2; + mnBase_dbg2 = mnBase_dbg1; // maybe_null_dbg = maybe_null_dbg + mnBase_dbg2 = nnBase; // maybe_null_dbg = not_null + + maybe_null_dbg mnDerived_dbg(&derived); + CHECK(mnDerived_dbg.present()); + mnBase_dbg2 = mnDerived_dbg; // maybe_null_dbg = maybe_null_dbg + + mnBase_dbg1 = &derived; // maybe_null_dbg = U; + mnBase_dbg1 = nnDerived; // maybe_null_dbg = not_null + + maybe_null_dbg mnUnrelated_dbg; + mnUnrelated_dbg = &unrelated; // maybe_null_dbg = T + } } int main(int, const char *[]) diff --git a/tests/notnull_tests.cpp b/tests/notnull_tests.cpp index 7232840..46011b6 100644 --- a/tests/notnull_tests.cpp +++ b/tests/notnull_tests.cpp @@ -65,12 +65,19 @@ SUITE(NotNullTests) TEST(TestNotNullCasting) { - MyDerived derived; + MyBase base; + MyDerived derived; + Unrelated unrelated; + not_null u = &unrelated; not_null p = &derived; - not_null q = p; + not_null q = &base; + q = p; // allowed with heterogeneous copy ctor CHECK(q == p); #ifdef CONFIRM_COMPILATION_ERRORS + q = u; // no viable conversion possible between MyBase* and Unrelated* + p = q; // not possible to implicitly convert MyBase* to MyDerived* + not_null r = p; not_null s = reinterpret_cast(p); #endif