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
#define BLACKMISC_OPTIONAL_H
#include "blackmisc/typetraits.h"
#include <QtGlobal>
#include <utility>
@@ -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<T>::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<T>::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<T>::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<T>::value)
Optional &operator =(Optional &&other) noexcept(std::is_nothrow_move_constructible<T>::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 <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)
{

View File

@@ -12,6 +12,9 @@
#ifndef 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)
#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 <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.
*/