noexcept adjustments in Optional<T>

This commit is contained in:
Mathew Sutcliffe
2017-01-04 22:11:49 +00:00
parent 67ffb41b27
commit 5ea9b90e87
2 changed files with 33 additions and 10 deletions

View File

@@ -12,6 +12,7 @@
#ifndef BLACKMISC_OPTIONAL_H #ifndef BLACKMISC_OPTIONAL_H
#define BLACKMISC_OPTIONAL_H #define BLACKMISC_OPTIONAL_H
#include "blackmisc/typetraits.h"
#include <QtGlobal> #include <QtGlobal>
#include <utility> #include <utility>
@@ -26,16 +27,20 @@ namespace BlackMisc
{ {
public: public:
//! Default constructor. //! Default constructor.
Optional() {} Optional() noexcept {}
//! Construct from a value. //! 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<T>::value)
{
new (m_data.bytes) T(std::move(value));
m_isValid = true;
}
//! Construct from a nullptr, equivalent to default constructor. //! Construct from a nullptr, equivalent to default constructor.
Optional(std::nullptr_t) {} Optional(std::nullptr_t) noexcept {}
//! Copy constructor. //! Copy constructor.
Optional(const Optional &other) Optional(const Optional &other) noexcept(std::is_nothrow_copy_constructible<T>::value)
{ {
if (other.m_isValid) { new (m_data.bytes) T(*other); } if (other.m_isValid) { new (m_data.bytes) T(*other); }
m_isValid = other.m_isValid; m_isValid = other.m_isValid;
@@ -49,14 +54,14 @@ namespace BlackMisc
} }
//! Assign a nullptr. //! Assign a nullptr.
Optional &operator =(std::nullptr_t) Optional &operator =(std::nullptr_t) noexcept
{ {
reset(); reset();
return *this; return *this;
} }
//! Copy assignment. //! Copy assignment.
Optional &operator =(const Optional &other) Optional &operator =(const Optional &other) noexcept(std::is_nothrow_copy_constructible<T>::value)
{ {
reset(); reset();
if (other.m_isValid) { new (m_data.bytes) T(*other); } if (other.m_isValid) { new (m_data.bytes) T(*other); }
@@ -65,7 +70,7 @@ namespace BlackMisc
} }
//! Move assignment. //! Move assignment.
Optional &operator =(Optional &&other) noexcept(std::is_nothrow_move_assignable<T>::value) Optional &operator =(Optional &&other) noexcept(std::is_nothrow_move_constructible<T>::value)
{ {
reset(); reset();
if (other.m_isValid) { new (m_data.bytes) T(std::move(*other)); } if (other.m_isValid) { new (m_data.bytes) T(std::move(*other)); }
@@ -77,7 +82,7 @@ namespace BlackMisc
~Optional() { if (m_isValid) { (*this)->~T(); } } ~Optional() { if (m_isValid) { (*this)->~T(); } }
//! Explicit cast to bool, true if this Optional contains a value. //! 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. //! If object is valid, destroy to make it invalid.
void reset() noexcept void reset() noexcept
@@ -115,10 +120,9 @@ namespace BlackMisc
/*! /*!
* Efficient swap for two Optional objects. * Efficient swap for two Optional objects.
* \todo Make conditionally noexcept using C++17 std::is_nothrow_swappable.
*/ */
template <typename T> template <typename T>
void swap(Optional<T> &a, Optional<T> &b) void swap(Optional<T> &a, Optional<T> &b) noexcept(Private::is_nothrow_swappable<T, T>::value)
{ {
if (a) if (a)
{ {

View File

@@ -12,6 +12,9 @@
#ifndef BLACKMISC_TYPETRAITS_H #ifndef BLACKMISC_TYPETRAITS_H
#define BLACKMISC_TYPETRAITS_H #define BLACKMISC_TYPETRAITS_H
#include <type_traits>
#include <utility> // for std::swap
#if defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && __GNUC__ >= 5) #if defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && __GNUC__ >= 5)
#define BLACK_HAS_FIXED_CWG1558 #define BLACK_HAS_FIXED_CWG1558
#endif #endif
@@ -38,6 +41,22 @@ namespace BlackMisc
#endif #endif
//! \endcond //! \endcond
namespace Private
{
//! \private Own implementation of C++17 std::is_nothrow_swappable.
template <typename T, typename U>
struct is_nothrow_swappable
{
static constexpr bool impl()
{
using std::swap;
return noexcept(swap(std::declval<T>(), std::declval<U>()))
&& noexcept(swap(std::declval<U>(), std::declval<T>()));
}
static constexpr bool value = impl();
};
}
/*! /*!
* Trait to detect whether T contains a member function toQString. * Trait to detect whether T contains a member function toQString.
*/ */