From e3fecbd1c5388a31b7d541009ed6081214458450 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Mon, 13 Feb 2017 11:40:27 -0800 Subject: [PATCH] not_null cleanups and improvements: (#449) * constexpr all the things. * remove operator=(const T&) * it leaves *this in an invalid state if ensure_invariant fails * implicitly converting the T to not_null and then assigning is in every way superior. * simplify conversion from not_null with constructor delegation. * remove the converting assignment operator; again let the conversion constructor and self-assignment operator do the work. * Cover the remaining pointer arithmetic operations as Wakely suggests in issue #447. * Cleanup not_null conversions from null pointer constants: * replace constructor that accepts T with constructor template that accepts U convertible to T * remove deleted constructor that accepts int * Attempts to initialize with nullptr, 0, 0L, 0LL, etc. all unambiguously select the deleted nullptr_t constructor. --- include/gsl/gsl | 84 +++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 51 deletions(-) diff --git a/include/gsl/gsl b/include/gsl/gsl index 76eb0be6..43b27bcc 100644 --- a/include/gsl/gsl +++ b/include/gsl/gsl @@ -62,81 +62,63 @@ using owner = T; // Has zero size overhead over T. // // If T is a pointer (i.e. T == U*) then -// - allow construction from U* or U& +// - allow construction from U* // - disallow construction from nullptr_t // - disallow default construction -// - ensure construction from U* fails with nullptr +// - ensure construction from null U* fails // - allow implicit conversion to U* // template class not_null { +public: static_assert(std::is_assignable::value, "T cannot be assigned nullptr."); -public: - not_null(T t) : ptr_(t) { ensure_invariant(); } - not_null& operator=(const T& t) - { - ptr_ = t; - ensure_invariant(); - return *this; - } + template ::value>> + constexpr not_null(U&& u) : ptr_(std::forward(u)) { Expects(ptr_ != nullptr); } + + template ::value>> + constexpr not_null(const not_null& other) : not_null(other.get()) {} not_null(const not_null& other) = default; not_null& operator=(const not_null& other) = default; - template ::value>> - not_null(const not_null& other) + constexpr T get() const { - *this = other; + Ensures(ptr_ != nullptr); + return ptr_; } - template ::value>> - not_null& operator=(const not_null& other) - { - ptr_ = other.get(); - return *this; - } + constexpr operator T() const { return get(); } + constexpr T operator->() const { return get(); } - // prevents compilation when someone attempts to assign a nullptr + // prevents compilation when someone attempts to assign a null pointer constant not_null(std::nullptr_t) = delete; - not_null(int) = delete; - not_null& operator=(std::nullptr_t) = delete; - not_null& operator=(int) = delete; + not_null& operator=(std::nullptr_t) = delete; - T get() const - { -#ifdef _MSC_VER - __assume(ptr_ != nullptr); -#endif - return ptr_; - } // the assume() should help the optimizer - - operator T() const { return get(); } - T operator->() const { return get(); } + // unwanted operators...pointers only point to single objects! + not_null& operator++() = delete; + not_null& operator--() = delete; + not_null operator++(int) = delete; + not_null operator--(int) = delete; + not_null& operator+=(std::ptrdiff_t) = delete; + not_null& operator-=(std::ptrdiff_t) = delete; + void operator[](std::ptrdiff_t) const = delete; - bool operator==(const T& rhs) const { return ptr_ == rhs; } - bool operator!=(const T& rhs) const { return !(*this == rhs); } private: T ptr_; - - // we assume that the compiler can hoist/prove away most of the checks inlined from this - // function - // if not, we could make them optional via conditional compilation - void ensure_invariant() const { Expects(ptr_ != nullptr); } - - // unwanted operators...pointers only point to single objects! - // TODO ensure all arithmetic ops on this type are unavailable - not_null& operator++() = delete; - not_null& operator--() = delete; - not_null operator++(int) = delete; - not_null operator--(int) = delete; - not_null& operator+(size_t) = delete; - not_null& operator+=(size_t) = delete; - not_null& operator-(size_t) = delete; - not_null& operator-=(size_t) = delete; }; +// more unwanted operators +template +std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; +template +not_null operator-(const not_null&, std::ptrdiff_t) = delete; +template +not_null operator+(const not_null&, std::ptrdiff_t) = delete; +template +not_null operator+(std::ptrdiff_t, const not_null&) = delete; + } // namespace gsl namespace std