diff --git a/src/blackmisc/optional.h b/src/blackmisc/optional.h index 4ce6a06e3..88c9ccc81 100644 --- a/src/blackmisc/optional.h +++ b/src/blackmisc/optional.h @@ -12,6 +12,7 @@ #ifndef BLACKMISC_OPTIONAL_H #define BLACKMISC_OPTIONAL_H +#include "blackmisc/typetraits.h" #include #include @@ -26,16 +27,20 @@ namespace BlackMisc { public: //! Default constructor. - Optional() {} + Optional() noexcept {} //! Construct from a value. - Optional(T value) { new (m_data.bytes) T(std::move(value)); m_isValid = true; } + Optional(T value) noexcept(std::is_nothrow_move_constructible::value) + { + new (m_data.bytes) T(std::move(value)); + m_isValid = true; + } //! Construct from a nullptr, equivalent to default constructor. - Optional(std::nullptr_t) {} + Optional(std::nullptr_t) noexcept {} //! Copy constructor. - Optional(const Optional &other) + Optional(const Optional &other) noexcept(std::is_nothrow_copy_constructible::value) { if (other.m_isValid) { new (m_data.bytes) T(*other); } m_isValid = other.m_isValid; @@ -49,14 +54,14 @@ namespace BlackMisc } //! Assign a nullptr. - Optional &operator =(std::nullptr_t) + Optional &operator =(std::nullptr_t) noexcept { reset(); return *this; } //! Copy assignment. - Optional &operator =(const Optional &other) + Optional &operator =(const Optional &other) noexcept(std::is_nothrow_copy_constructible::value) { reset(); if (other.m_isValid) { new (m_data.bytes) T(*other); } @@ -65,7 +70,7 @@ namespace BlackMisc } //! Move assignment. - Optional &operator =(Optional &&other) noexcept(std::is_nothrow_move_assignable::value) + Optional &operator =(Optional &&other) noexcept(std::is_nothrow_move_constructible::value) { reset(); if (other.m_isValid) { new (m_data.bytes) T(std::move(*other)); } @@ -77,7 +82,7 @@ namespace BlackMisc ~Optional() { if (m_isValid) { (*this)->~T(); } } //! Explicit cast to bool, true if this Optional contains a value. - explicit operator bool() const { return m_isValid; } + explicit operator bool() const noexcept { return m_isValid; } //! If object is valid, destroy to make it invalid. void reset() noexcept @@ -115,10 +120,9 @@ namespace BlackMisc /*! * Efficient swap for two Optional objects. - * \todo Make conditionally noexcept using C++17 std::is_nothrow_swappable. */ template - void swap(Optional &a, Optional &b) + void swap(Optional &a, Optional &b) noexcept(Private::is_nothrow_swappable::value) { if (a) { diff --git a/src/blackmisc/typetraits.h b/src/blackmisc/typetraits.h index 9ed1236fc..bcfd79d82 100644 --- a/src/blackmisc/typetraits.h +++ b/src/blackmisc/typetraits.h @@ -12,6 +12,9 @@ #ifndef BLACKMISC_TYPETRAITS_H #define BLACKMISC_TYPETRAITS_H +#include +#include // for std::swap + #if defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && __GNUC__ >= 5) #define BLACK_HAS_FIXED_CWG1558 #endif @@ -38,6 +41,22 @@ namespace BlackMisc #endif //! \endcond + namespace Private + { + //! \private Own implementation of C++17 std::is_nothrow_swappable. + template + struct is_nothrow_swappable + { + static constexpr bool impl() + { + using std::swap; + return noexcept(swap(std::declval(), std::declval())) + && noexcept(swap(std::declval(), std::declval())); + } + static constexpr bool value = impl(); + }; + } + /*! * Trait to detect whether T contains a member function toQString. */