mirror of
https://github.com/TartanLlama/optional.git
synced 2025-08-05 20:44:27 +02:00
Trivial destructor
This commit is contained in:
843
optional.hpp
843
optional.hpp
@@ -55,20 +55,20 @@ namespace tl {
|
|||||||
};
|
};
|
||||||
static constexpr in_place_t in_place{};
|
static constexpr in_place_t in_place{};
|
||||||
|
|
||||||
// [optional.optional], class template optional
|
// [optional.optional], class template optional
|
||||||
template <class T>
|
template <class T>
|
||||||
class optional;
|
class optional;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
using enable_forward_value = tl::enable_if_t<
|
using enable_forward_value = enable_if_t<
|
||||||
std::is_constructible<T, U&&>::value &&
|
std::is_constructible<T, U&&>::value &&
|
||||||
!std::is_same<tl::decay_t<U>, in_place_t>::value &&
|
!std::is_same<tl::decay_t<U>, in_place_t>::value &&
|
||||||
!std::is_same<optional<T>, tl::decay_t<U>>::value
|
!std::is_same<optional<T>, tl::decay_t<U>>::value
|
||||||
>;
|
>;
|
||||||
|
|
||||||
template <class T, class U, class Other>
|
template <class T, class U, class Other>
|
||||||
using enable_from_other = tl::enable_if_t<
|
using enable_from_other = enable_if_t<
|
||||||
std::is_constructible<T, Other>::value &&
|
std::is_constructible<T, Other>::value &&
|
||||||
!std::is_constructible<T, optional<U>&>::value &&
|
!std::is_constructible<T, optional<U>&>::value &&
|
||||||
!std::is_constructible<T, optional<U>&&>::value &&
|
!std::is_constructible<T, optional<U>&&>::value &&
|
||||||
@@ -78,58 +78,59 @@ namespace tl {
|
|||||||
!std::is_convertible<optional<U>&&, T>::value &&
|
!std::is_convertible<optional<U>&&, T>::value &&
|
||||||
!std::is_convertible<const optional<U>&, T>::value &&
|
!std::is_convertible<const optional<U>&, T>::value &&
|
||||||
!std::is_convertible<const optional<U>&&, T>::value
|
!std::is_convertible<const optional<U>&&, T>::value
|
||||||
>;
|
>;
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
using enable_assign_forward = tl::enable_if_t<
|
using enable_assign_forward = enable_if_t<
|
||||||
!is_same_v<optional<T>, tl::decay_t<U>>::value &&
|
!std::is_same<optional<T>, tl::decay_t<U>>::value &&
|
||||||
!tl::conjunction<std::is_scalar<T>, std::is_same<T, tl::decay_t<U>>>::value &&
|
!tl::conjunction<std::is_scalar<T>, std::is_same<T, tl::decay_t<U>>>::value &&
|
||||||
std::is_constructible<T, U>::value &&
|
std::is_constructible<T, U>::value &&
|
||||||
is_assignable<T&, U>::value
|
std::is_assignable<T&, U>::value
|
||||||
>;
|
>;
|
||||||
|
|
||||||
template <class T, class U, class Other>
|
template <class T, class U, class Other>
|
||||||
using enable_assign_from_other = tl::enable_if_t<
|
using enable_assign_from_other = enable_if_t<
|
||||||
std::is_constructible<T, Other> &&
|
std::is_constructible<T, Other>::value &&
|
||||||
std::is_assignablev<T&, Other> &&
|
std::is_assignable<T&, Other>::value &&
|
||||||
!std::is_constructiblev<T, optional<U>&> &&
|
!std::is_constructible<T, optional<U>&>::value &&
|
||||||
!std::is_constructiblev<T, optional<U>&&> &&
|
!std::is_constructible<T, optional<U>&&>::value &&
|
||||||
!std::is_constructiblev<T, const optional<U>&> &&
|
!std::is_constructible<T, const optional<U>&>::value &&
|
||||||
!std::is_constructiblev<T, const optional<U>&&> &&
|
!std::is_constructible<T, const optional<U>&&>::value &&
|
||||||
!std::is_convertiblev<optional<U>&, T> &&
|
!std::is_convertible<optional<U>&, T>::value &&
|
||||||
!std::is_convertiblev<optional<U>&&, T> &&
|
!std::is_convertible<optional<U>&&, T>::value &&
|
||||||
!std::is_convertiblev<const optional<U>&, T> &&
|
!std::is_convertible<const optional<U>&, T>::value &&
|
||||||
!std::is_convertiblev<const optional<U>&&, T> &&
|
!std::is_convertible<const optional<U>&&, T>::value &&
|
||||||
!std::is_assignablev<T&, optional<U>&> &&
|
!std::is_assignable<T&, optional<U>&>::value &&
|
||||||
!std::is_assignablev<T&, optional<U>&&> &&
|
!std::is_assignable<T&, optional<U>&&>::value &&
|
||||||
!std::is_assignablev<T&, const optional<U>&> &&
|
!std::is_assignable<T&, const optional<U>&>::value &&
|
||||||
!std::is_assignablev<T&, const optional<U>&&>
|
!std::is_assignable<T&, const optional<U>&&>::value
|
||||||
>
|
>;
|
||||||
|
|
||||||
//TODO improve
|
//TODO improve
|
||||||
template <class T, class=void>
|
template <class T, class=void>
|
||||||
struct is_swappable : std::false_type{};
|
struct is_swappable : std::false_type{};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct is_swappable<T,void_t<decltype(swap(std::declval<T>(), std::declval<T>()))>>
|
struct is_swappable<T,void_t<decltype(swap(std::declval<T>(), std::declval<T>()))>>
|
||||||
: std::true_type{};
|
: std::true_type{};
|
||||||
|
|
||||||
//TODO improve
|
//TODO improve
|
||||||
template <class T, class=void>
|
template <class T, class=void>
|
||||||
struct is_nothrow_swappable : std::false_type{};
|
struct is_nothrow_swappable : std::false_type{};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct is_nothrow_swappable<T,void_t<decltype(swap(std::declval<T>(), std::declval<T>()))>>
|
struct is_nothrow_swappable<T,void_t<decltype(swap(std::declval<T>(), std::declval<T>()))>>
|
||||||
: std::true_type{};
|
: std::true_type{};
|
||||||
|
}
|
||||||
|
|
||||||
// [optional.nullopt], no-value state indicator
|
// [optional.nullopt], no-value state indicator
|
||||||
struct nullopt_t{
|
struct nullopt_t{
|
||||||
struct do_not_use{};
|
struct do_not_use{};
|
||||||
constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept{}
|
constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept{}
|
||||||
};
|
};
|
||||||
static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}};
|
static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}};
|
||||||
|
|
||||||
// [optional.bad.access], class bad_optional_access
|
// [optional.bad.access], class bad_optional_access
|
||||||
class bad_optional_access : public std::exception {
|
class bad_optional_access : public std::exception {
|
||||||
public:
|
public:
|
||||||
bad_optional_access() = default;
|
bad_optional_access() = default;
|
||||||
@@ -138,158 +139,158 @@ namespace tl {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// [optional.relops], relational operators
|
// [optional.relops], relational operators
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (lhs.has_value() != rhs.has_value())
|
if (lhs.has_value() != rhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
if (lhs.has_value())
|
if (lhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return lhs.value() == rhs.value();
|
return lhs.value() == rhs.value();
|
||||||
}
|
}
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (lhs.has_value() != rhs.has_value())
|
if (lhs.has_value() != rhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
if (lhs.has_value())
|
if (lhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs.value() != rhs.value();
|
return lhs.value() != rhs.value();
|
||||||
}
|
}
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (!rhs.has_value())
|
if (!rhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
if (!lhs.has_value())
|
if (!lhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return lhs.value() < rhs.value();
|
return lhs.value() < rhs.value();
|
||||||
}
|
}
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (!lhs.has_value())
|
if (!lhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
if (!rhs.has_value())
|
if (!rhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return lhs.value() > rhs.value();
|
return lhs.value() > rhs.value();
|
||||||
}
|
}
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (!lhs.has_value())
|
if (!lhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
if (!rhs.has_value())
|
if (!rhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs.value() <= rhs.value();
|
return lhs.value() <= rhs.value();
|
||||||
}
|
}
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
|
inline constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||||
if (!rhs.has_value())
|
if (!rhs.has_value())
|
||||||
return true;
|
return true;
|
||||||
if (!lhs.has_value())
|
if (!lhs.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs.value() >= rhs.value();
|
return lhs.value() >= rhs.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// [optional.nullops], comparison with nullopt
|
// [optional.nullops], comparison with nullopt
|
||||||
template <class T> inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator==(const optional<T>& lhs, nullopt_t) noexcept {
|
||||||
return !lhs.has_value();
|
return !lhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept {
|
template <class T> inline constexpr bool operator==(nullopt_t, const optional<T>& rhs) noexcept {
|
||||||
return !rhs.has_value();
|
return !rhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator!=(const optional<T>& lhs, nullopt_t) noexcept {
|
||||||
return lhs.has_value();
|
return lhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept {
|
template <class T> inline constexpr bool operator!=(nullopt_t, const optional<T>& rhs) noexcept {
|
||||||
return rhs.has_value();
|
return rhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept {
|
template <class T> inline constexpr bool operator<(nullopt_t, const optional<T>& rhs) noexcept {
|
||||||
return rhs.has_value();
|
return rhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator<=(const optional<T>& lhs, nullopt_t) noexcept {
|
||||||
return !lhs.has_value();
|
return !lhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
|
template <class T> inline constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator>(const optional<T>& lhs, nullopt_t) noexcept {
|
||||||
return lhs.has_value();
|
return lhs.has_value();
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
|
template <class T> inline constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
|
template <class T> inline constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template <class T> inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept {
|
template <class T> inline constexpr bool operator>=(nullopt_t, const optional<T>& rhs) noexcept {
|
||||||
return !rhs.has_value();
|
return !rhs.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// [optional.comp_with_t], comparison with T
|
// [optional.comp_with_t], comparison with T
|
||||||
template <class T, class U> inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator==(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? *lhs == rhs : false;
|
return lhs.has_value() ? *lhs == rhs : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator==(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs == rhs.value() : false;
|
return rhs.has_value() ? lhs == rhs.value() : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator!=(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? lhs.value() != lhs : true;
|
return lhs.has_value() ? lhs.value() != lhs : true;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator!=(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs != rhs.value() : true;
|
return rhs.has_value() ? lhs != rhs.value() : true;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator<(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? lhs.value() < lhs : true;
|
return lhs.has_value() ? lhs.value() < lhs : true;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator<(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs < rhs.value() : false;
|
return rhs.has_value() ? lhs < rhs.value() : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator<=(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? lhs.value() <= lhs : true;
|
return lhs.has_value() ? lhs.value() <= lhs : true;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator<=(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs <= rhs.value() : false;
|
return rhs.has_value() ? lhs <= rhs.value() : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator>(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? lhs.value() > lhs : false;
|
return lhs.has_value() ? lhs.value() > lhs : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator>(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs > rhs.value() : true;
|
return rhs.has_value() ? lhs > rhs.value() : true;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) {
|
template <class T, class U> inline constexpr bool operator>=(const optional<T>& lhs, const U& rhs) {
|
||||||
return lhs.has_value() ? lhs.value() >= lhs : false;
|
return lhs.has_value() ? lhs.value() >= lhs : false;
|
||||||
}
|
}
|
||||||
template <class T, class U> inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) {
|
template <class T, class U> inline constexpr bool operator>=(const U& lhs, const optional<T>& rhs) {
|
||||||
return rhs.has_value() ? lhs >= rhs.value() : true;
|
return rhs.has_value() ? lhs >= rhs.value() : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// [optional.specalg], specialized algorithms
|
// [optional.specalg], specialized algorithms
|
||||||
template <class T, tl::enable_if_t<std::is_move_constructible<T>::value>* = nullptr,
|
template <class T, enable_if_t<std::is_move_constructible<T>::value>* = nullptr,
|
||||||
tl::enable_if_t<is_swappable<T>::value>* = nullptr>
|
enable_if_t<detail::is_swappable<T>::value>* = nullptr>
|
||||||
void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
void swap(optional<T>& lhs, optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
||||||
return lhs.swap(rhs);
|
return lhs.swap(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline constexpr optional<tl::decay_t<T>> make_optional(T&& v) {
|
inline constexpr optional<tl::decay_t<T>> make_optional(T&& v) {
|
||||||
return optional<decay_t<T>>(std::forward<T>(v));
|
return optional<decay_t<T>>(std::forward<T>(v));
|
||||||
}
|
}
|
||||||
template <class T, class... Args>
|
template <class T, class... Args>
|
||||||
inline constexpr optional<T> make_optional(Args&&... args) {
|
inline constexpr optional<T> make_optional(Args&&... args) {
|
||||||
return optional<T>(in_place, std::forward<Args>(args)...);
|
return optional<T>(in_place, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
template <class T, class U, class... Args>
|
template <class T, class U, class... Args>
|
||||||
inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) {
|
inline constexpr optional<T> make_optional(std::initializer_list<U> il, Args&&... args) {
|
||||||
return optional<T>(in_place, il, std::forward<Args>(args)...);
|
return optional<T>(in_place, il, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [optional.hash], hash support
|
// [optional.hash], hash support
|
||||||
@@ -297,7 +298,7 @@ namespace std {
|
|||||||
//TODO SFINAE
|
//TODO SFINAE
|
||||||
template <class T>
|
template <class T>
|
||||||
struct hash<tl::optional<T>> {
|
struct hash<tl::optional<T>> {
|
||||||
std::size_t operator() (const tl::optional<T>& o) const {
|
::std::size_t operator() (const tl::optional<T>& o) const {
|
||||||
if (!o.has_value())
|
if (!o.has_value())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -307,9 +308,8 @@ namespace std {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace tl {
|
namespace tl {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <class T, bool = std::is_trivially_destructible<T>::value>
|
template <class T, bool = ::std::is_trivially_destructible<T>::value>
|
||||||
struct optional_storage_base {
|
struct optional_storage_base {
|
||||||
constexpr optional_storage_base() noexcept
|
constexpr optional_storage_base() noexcept
|
||||||
: m_dummy(), m_has_value(false) {}
|
: m_dummy(), m_has_value(false) {}
|
||||||
@@ -333,12 +333,7 @@ namespace tl {
|
|||||||
struct optional_storage_base<T, true> {
|
struct optional_storage_base<T, true> {
|
||||||
constexpr optional_storage_base() noexcept
|
constexpr optional_storage_base() noexcept
|
||||||
: m_dummy(), m_has_value(false) {}
|
: m_dummy(), m_has_value(false) {}
|
||||||
~optional_storage_base() {
|
~optional_storage_base() = default;
|
||||||
if (m_has_value) {
|
|
||||||
//don't destruct value
|
|
||||||
m_has_value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dummy{};
|
struct dummy{};
|
||||||
union {
|
union {
|
||||||
@@ -350,273 +345,273 @@ namespace tl {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class optional : private detail::optional_storage_base<T> {
|
class optional : private detail::optional_storage_base<T> {
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
// [optional.ctor], constructors
|
// [optional.ctor], constructors
|
||||||
constexpr optional() noexcept = default;
|
constexpr optional() noexcept = default;
|
||||||
constexpr optional(nullopt_t) noexcept {};
|
constexpr optional(nullopt_t) noexcept {};
|
||||||
constexpr optional(const optional& rhs) {
|
constexpr optional(const optional& rhs) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (rhs.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <class U = T, enable_if_t<std::is_move_constructible<T>::value>* = nullptr>
|
||||||
|
constexpr optional(optional&& rhs) {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <class... Args>
|
||||||
|
constexpr explicit optional(enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
|
||||||
|
Args&&... args) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
template <class U, class... Args>
|
||||||
|
constexpr explicit optional(
|
||||||
|
enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>,
|
||||||
|
std::initializer_list<U> il, Args&&... args) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (il, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U = T, enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr,
|
||||||
|
detail::enable_forward_value<T,U>* = nullptr>
|
||||||
|
constexpr optional(U&& u) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U = T, enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr,
|
||||||
|
detail::enable_forward_value<T,U>* = nullptr>
|
||||||
|
constexpr explicit optional(U&& u) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U, detail::enable_from_other<T,U,const U&>* = nullptr,
|
||||||
|
enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr>
|
||||||
|
optional(const optional<U>& rhs) {
|
||||||
this->m_has_value = true;
|
this->m_has_value = true;
|
||||||
new (std::addressof(this->m_value)) T (rhs.value());
|
new (std::addressof(this->m_value)) T (rhs.value());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
template <class U = T, tl::enable_if_t<std::is_move_constructible<T>::value>* = nullptr>
|
template <class U, detail::enable_from_other<T,U,const U&>* = nullptr,
|
||||||
constexpr optional(optional&& rhs) {
|
enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr>
|
||||||
|
optional(const optional<U>& rhs) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (rhs.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr,
|
||||||
|
enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr>
|
||||||
|
optional(optional<U>&& rhs) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr,
|
||||||
|
enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr>
|
||||||
|
explicit optional(optional<U>&& rhs) {
|
||||||
|
this->m_has_value = true;
|
||||||
|
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// [optional.dtor], destructor
|
||||||
|
~optional() = default;
|
||||||
|
|
||||||
|
// [optional.assign], assignment
|
||||||
|
optional& operator=(nullopt_t) noexcept {
|
||||||
|
if (has_value()) {
|
||||||
|
this->m_value.~T();
|
||||||
|
this->m_has_value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO conditionally delete, check exception guarantee
|
||||||
|
optional& operator=(const optional& rhs) {
|
||||||
|
if (has_value()) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->m_has_value = true;
|
this->m_value = rhs.m_value;
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
}
|
||||||
|
else {
|
||||||
|
this->m_value.~T();
|
||||||
|
this->m_has_value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <class... Args>
|
|
||||||
constexpr explicit optional(tl::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
|
|
||||||
Args&&... args) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
template <class U, class... Args>
|
|
||||||
constexpr explicit optional(
|
|
||||||
tl::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, in_place_t>,
|
|
||||||
std::initializer_list<U> il, Args&&... args) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (il, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U = T, tl::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr,
|
|
||||||
detail::enable_forward_value<T,U>* = nullptr>
|
|
||||||
constexpr optional(U&& u) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U = T, tl::enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr,
|
|
||||||
detail::enable_forward_value<T,U>* = nullptr>
|
|
||||||
constexpr explicit optional(U&& u) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U, detail::enable_from_other<T,U,const U&>* = nullptr,
|
|
||||||
tl::enable_if_t<std::is_convertible<const U&, T>::value>* = nullptr>
|
|
||||||
optional(const optional<U>& rhs) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (rhs.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U, detail::enable_from_other<T,U,const U&>* = nullptr,
|
|
||||||
tl::enable_if_t<!std::is_convertible<const U&, T>::value>* = nullptr>
|
|
||||||
optional(const optional<U>& rhs) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (rhs.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr,
|
|
||||||
tl::enable_if_t<std::is_convertible<U&&, T>::value>* = nullptr>
|
|
||||||
optional(optional<U>&& rhs) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class U, detail::enable_from_other<T,U,U&&>* = nullptr,
|
|
||||||
enable_if_t<!std::is_convertible<U&&, T>::value>* = nullptr>
|
|
||||||
explicit optional(optional<U>&& rhs) {
|
|
||||||
this->m_has_value = true;
|
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// [optional.dtor], destructor
|
|
||||||
~optional() = default;
|
|
||||||
|
|
||||||
// [optional.assign], assignment
|
|
||||||
optional& operator=(nullopt_t) noexcept {
|
|
||||||
if (has_value()) {
|
|
||||||
this->m_value.~T();
|
|
||||||
this->m_has_value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO conditionally delete, check exception guarantee
|
|
||||||
optional& operator=(const optional& rhs) {
|
|
||||||
if (has_value()) {
|
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->m_value = rhs.m_value;
|
new (std::addressof(this->m_value)) T (rhs.m_value);
|
||||||
}
|
this->m_has_value = true;
|
||||||
else {
|
|
||||||
this->m_value.~T();
|
|
||||||
this->m_has_value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs.has_value()) {
|
// TODO conditionally delete, check exception guarantee
|
||||||
new (std::addressof(this->m_value)) T (rhs.m_value);
|
optional& operator=(optional&& rhs) noexcept {
|
||||||
this->m_has_value = true;
|
if (has_value()) {
|
||||||
}
|
if (rhs.has_value()) {
|
||||||
}
|
this->m_value = std::move(rhs.m_value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->m_value.~T();
|
||||||
|
this->m_has_value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO conditionally delete, check exception guarantee
|
|
||||||
optional& operator=(optional&& rhs) noexcept {
|
|
||||||
if (has_value()) {
|
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->m_value = std::move(rhs.m_value);
|
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
||||||
}
|
this->m_has_value = true;
|
||||||
else {
|
|
||||||
this->m_value.~T();
|
|
||||||
this->m_has_value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs.has_value()) {
|
// TODO conditionally delete, check exception guarantee
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
template <class U = T,
|
||||||
this->m_has_value = true;
|
detail::enable_assign_forward<T,U>* = nullptr>
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO conditionally delete, check exception guarantee
|
|
||||||
template <class U = T,
|
|
||||||
detail::enable_assign_forward<T,U>* = nullptr>
|
|
||||||
optional& operator=(U&& u) {
|
optional& operator=(U&& u) {
|
||||||
if (has_value()) {
|
if (has_value()) {
|
||||||
this->m_value = std::forward<U>(u);
|
this->m_value = std::forward<U>(u);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
||||||
|
this->m_has_value = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
new (std::addressof(this->m_value)) T (std::forward<U>(u));
|
|
||||||
this->m_has_value = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO SFINAE, check exception guarantee
|
// TODO check exception guarantee
|
||||||
template <class U, detail::enable_assign_from_other<T,U,const U&>* = nullptr>
|
template <class U, detail::enable_assign_from_other<T,U,const U&>* = nullptr>
|
||||||
optional& operator=(const optional<U>& rhs) {
|
optional& operator=(const optional<U>& rhs) {
|
||||||
if (has_value()) {
|
if (has_value()) {
|
||||||
|
if (rhs.has_value()) {
|
||||||
|
this->m_value = rhs.m_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->m_value.~T();
|
||||||
|
this->m_has_value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->m_value = rhs.m_value;
|
new (std::addressof(this->m_value)) T (rhs.m_value);
|
||||||
}
|
this->m_has_value = true;
|
||||||
else {
|
|
||||||
this->m_value.~T();
|
|
||||||
this->m_has_value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs.has_value()) {
|
// TODO check exception guarantee
|
||||||
new (std::addressof(this->m_value)) T (rhs.m_value);
|
template <class U, detail::enable_assign_from_other<T,U,U>* = nullptr>
|
||||||
this->m_has_value = true;
|
optional& operator=(optional<U>&& rhs) {
|
||||||
}
|
if (has_value()) {
|
||||||
}
|
if (rhs.has_value()) {
|
||||||
|
this->m_value = std::move(rhs.m_value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->m_value.~T();
|
||||||
|
this->m_has_value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO SFINAE, check exception guarantee
|
|
||||||
template <class U, detail::enable_assign_from_other<T,U,U>* = nullptr>
|
|
||||||
optional& operator=(optional<U>&& rhs) {
|
|
||||||
if (has_value()) {
|
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
this->m_value = std::move(rhs.m_value);
|
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
||||||
}
|
this->m_has_value = true;
|
||||||
else {
|
|
||||||
this->m_value.~T();
|
|
||||||
this->m_has_value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhs.has_value()) {
|
template <class... Args> T& emplace(Args&&... args) {
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
static_assert(std::is_constructible<T, Args&&...>::value,
|
||||||
this->m_has_value = true;
|
"T must be constructible with Args");
|
||||||
|
|
||||||
|
*this = nullopt;
|
||||||
|
new (std::addressof(this->m_value)) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <class... Args> T& emplace(Args&&... args) {
|
template <class U, class... Args>
|
||||||
static_assert(std::is_constructible<T, Args&&...>::value,
|
enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&>
|
||||||
"T must be constructible with Args");
|
emplace(std::initializer_list<U> il, Args&&... args) {
|
||||||
|
*this = nullopt;
|
||||||
|
new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
*this = nullopt;
|
// [optional.swap], swap
|
||||||
new (std::addressof(this->m_value)) T(std::forward<Args>(args)...);
|
void swap(optional& rhs)
|
||||||
}
|
noexcept(std::is_nothrow_move_constructible<T>::value && detail::is_nothrow_swappable<T>::value)
|
||||||
|
{
|
||||||
template <class U, class... Args>
|
if (has_value()) {
|
||||||
tl::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, T&>
|
if (rhs.has_value()) {
|
||||||
emplace(std::initializer_list<U> il, Args&&... args) {
|
using std::swap;
|
||||||
*this = nullopt;
|
swap(value(), rhs.value());
|
||||||
new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...);
|
}
|
||||||
}
|
else {
|
||||||
|
new (&rhs.m_value) T (std::move(this->m_value));
|
||||||
// [optional.swap], swap
|
this->m_value.T::~T();
|
||||||
void swap(optional& rhs)
|
}
|
||||||
noexcept(std::is_nothrow_move_constructible<T>::value && is_nothrow_swappable<T>::value)
|
|
||||||
{
|
|
||||||
if (has_value()) {
|
|
||||||
if (rhs.has_value()) {
|
|
||||||
using std::swap;
|
|
||||||
swap(value(), rhs.value());
|
|
||||||
}
|
}
|
||||||
else {
|
else if (rhs.has_value()) {
|
||||||
new (&rhs.m_value) T (std::move(this->m_value));
|
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
||||||
this->m_value.T::~T();
|
rhs.m_value.T::~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rhs.has_value()) {
|
|
||||||
new (std::addressof(this->m_value)) T (std::move(rhs.m_value));
|
// [optional.observe], observers
|
||||||
rhs.m_value.T::~T();
|
constexpr const T* operator->() const {
|
||||||
|
return std::addressof(this->m_value);
|
||||||
|
}
|
||||||
|
constexpr T* operator->() {
|
||||||
|
return std::addressof(this->m_value);
|
||||||
|
}
|
||||||
|
constexpr const T& operator*() const& {
|
||||||
|
return this->m_value;
|
||||||
|
}
|
||||||
|
constexpr T& operator*() & {
|
||||||
|
return this->m_value;
|
||||||
|
}
|
||||||
|
constexpr T&& operator*() && {
|
||||||
|
return std::move(this->m_value);
|
||||||
|
}
|
||||||
|
constexpr const T&& operator*() const&& {
|
||||||
|
return std::move(this->m_value);
|
||||||
|
}
|
||||||
|
constexpr explicit operator bool() const noexcept {
|
||||||
|
return this->m_has_value;
|
||||||
|
}
|
||||||
|
constexpr bool has_value() const noexcept {
|
||||||
|
return this->m_has_value;
|
||||||
|
}
|
||||||
|
constexpr const T& value() const& {
|
||||||
|
if (has_value()) return this->m_value;
|
||||||
|
throw bad_optional_access();
|
||||||
|
}
|
||||||
|
constexpr T& value() & {
|
||||||
|
if (has_value()) return this->m_value;
|
||||||
|
throw bad_optional_access();
|
||||||
|
}
|
||||||
|
constexpr T&& value() && {
|
||||||
|
if (has_value()) return std::move(this->m_value);
|
||||||
|
throw bad_optional_access();
|
||||||
|
}
|
||||||
|
constexpr const T&& value() const&& {
|
||||||
|
if (has_value()) return std::move(this->m_value);
|
||||||
|
throw bad_optional_access();
|
||||||
|
}
|
||||||
|
template <class U> constexpr T value_or(U&& u) const& {
|
||||||
|
static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value,
|
||||||
|
"T must be copy constructible and convertible from U");
|
||||||
|
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
|
||||||
|
}
|
||||||
|
template <class U> constexpr T value_or(U&& u) && {
|
||||||
|
static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value,
|
||||||
|
"T must be move constructible and convertible from U");
|
||||||
|
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// [optional.observe], observers
|
// [optional.mod], modifiers
|
||||||
constexpr const T* operator->() const {
|
void reset() noexcept;
|
||||||
return std::addressof(this->m_value);
|
|
||||||
}
|
|
||||||
constexpr T* operator->() {
|
|
||||||
return std::addressof(this->m_value);
|
|
||||||
}
|
|
||||||
constexpr const T& operator*() const& {
|
|
||||||
return this->m_value;
|
|
||||||
}
|
|
||||||
constexpr T& operator*() & {
|
|
||||||
return this->m_value;
|
|
||||||
}
|
|
||||||
constexpr T&& operator*() && {
|
|
||||||
return std::move(this->m_value);
|
|
||||||
}
|
|
||||||
constexpr const T&& operator*() const&& {
|
|
||||||
return std::move(this->m_value);
|
|
||||||
}
|
|
||||||
constexpr explicit operator bool() const noexcept {
|
|
||||||
return this->m_has_value;
|
|
||||||
}
|
|
||||||
constexpr bool has_value() const noexcept {
|
|
||||||
return this->m_has_value;
|
|
||||||
}
|
|
||||||
constexpr const T& value() const& {
|
|
||||||
if (has_value()) return this->m_value;
|
|
||||||
throw bad_optional_access();
|
|
||||||
}
|
|
||||||
constexpr T& value() & {
|
|
||||||
if (has_value()) return this->m_value;
|
|
||||||
throw bad_optional_access();
|
|
||||||
}
|
|
||||||
constexpr T&& value() && {
|
|
||||||
if (has_value()) return std::move(this->m_value);
|
|
||||||
throw bad_optional_access();
|
|
||||||
}
|
|
||||||
constexpr const T&& value() const&& {
|
|
||||||
if (has_value()) return std::move(this->m_value);
|
|
||||||
throw bad_optional_access();
|
|
||||||
}
|
|
||||||
template <class U> constexpr T value_or(U&& u) const& {
|
|
||||||
static_assert(std::is_copy_constructible<T>::value && std::is_convertible<U&&, T>::value,
|
|
||||||
"T must be copy constructible and convertible from U");
|
|
||||||
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
|
|
||||||
}
|
|
||||||
template <class U> constexpr T value_or(U&& u) && {
|
|
||||||
static_assert(std::is_move_constructible<T>::value && std::is_convertible<U&&, T>::value,
|
|
||||||
"T must be move constructible and convertible from U");
|
|
||||||
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
|
|
||||||
}
|
|
||||||
|
|
||||||
// [optional.mod], modifiers
|
private:
|
||||||
void reset() noexcept;
|
|
||||||
|
|
||||||
private:
|
};
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user