.. _program_listing_file_src_navtk_not_null.hpp: Program Listing for File not_null.hpp ===================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/navtk/not_null.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include #include #include #include #include #include // Both forward declarations necessary here to allow a template class in one namespace to have a // friend function in a separate namespace. namespace navtk { template class not_null; } namespace std { template std::shared_ptr dynamic_pointer_cast(const navtk::not_null&) noexcept; } namespace navtk { template class not_null { public: static_assert(std::is_convertible() == nullptr), bool>::value, "T cannot be compared to nullptr"); template ::value>> constexpr not_null(T p) : ptr(std::move(p)) { if (ptr == nullptr) log_or_throw("Pointer must be non-null."); } template ::value>> constexpr not_null(U&& p) : ptr(std::forward(p)) { if (ptr == nullptr) log_or_throw("Pointer must be non-null."); } template ::value>> constexpr not_null(const not_null& other) : not_null(other.get()) {} not_null(const not_null& other) = default; not_null(not_null&& other) = default; not_null& operator=(const not_null& other) = default; not_null& operator=(not_null&& other) = default; constexpr std::conditional_t::value, T, const T&> get() const { if (ptr == nullptr) log_or_throw("Held pointer is no longer non-null."); return ptr; } constexpr operator T() const { return get(); } constexpr decltype(auto) operator->() const { return get(); } constexpr decltype(auto) operator*() const { return *get(); } void operator[](std::ptrdiff_t) const = delete; not_null(std::nullptr_t) = delete; not_null& operator=(std::nullptr_t) = delete; 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; template friend std::shared_ptr std::dynamic_pointer_cast(const navtk::not_null&) noexcept; private: T ptr; }; template auto make_not_null(T&& p) noexcept { return not_null>>{std::forward(p)}; } template std::ostream& operator<<(std::ostream& os, const not_null& val) { os << val.get(); return os; } template auto operator==(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() == rhs.get())) -> decltype(lhs.get() == rhs.get()) { return lhs.get() == rhs.get(); } template auto operator!=(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() != rhs.get())) -> decltype(lhs.get() != rhs.get()) { return lhs.get() != rhs.get(); } template auto operator<(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() < rhs.get())) -> decltype(lhs.get() < rhs.get()) { return lhs.get() < rhs.get(); } template auto operator<=(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() <= rhs.get())) -> decltype(lhs.get() <= rhs.get()) { return lhs.get() <= rhs.get(); } template auto operator>(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() > rhs.get())) -> decltype(lhs.get() > rhs.get()) { return lhs.get() > rhs.get(); } template auto operator>=(const not_null& lhs, const not_null& rhs) noexcept( noexcept(lhs.get() >= rhs.get())) -> decltype(lhs.get() >= rhs.get()) { return lhs.get() >= rhs.get(); } #ifndef NEED_DOXYGEN_EXHALE_WORKAROUND // Disable not_null pointer arithmetic addition/subtraction. 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; #endif } // namespace navtk namespace std { // Implementation of overload for `std::dynamic_pointer_cast` declared in `navtk::not_null`. template std::shared_ptr dynamic_pointer_cast(const navtk::not_null& p) noexcept { return dynamic_pointer_cast(p.ptr); } } // namespace std