forked from TartanLlama/optional
Initial support for references
This commit is contained in:
883
tl/optional.hpp
883
tl/optional.hpp
@ -176,8 +176,8 @@
|
||||
using disable_if_ret_void = enable_if_t<!returns_void<T &&, U...>::value>;
|
||||
|
||||
template <class T, class U>
|
||||
using enable_forward_value = detail::enable_if_t<
|
||||
std::is_constructible<T, U &&>::value &&
|
||||
using enable_forward_value =
|
||||
detail::enable_if_t<std::is_constructible<T, U &&>::value &&
|
||||
!std::is_same<detail::decay_t<U>, in_place_t>::value &&
|
||||
!std::is_same<optional<T>, detail::decay_t<U>>::value>;
|
||||
|
||||
@ -221,8 +221,7 @@
|
||||
// TODO make a version which works with MSVC
|
||||
template <class T, class U = T> struct is_swappable : std::true_type {};
|
||||
|
||||
template <class T, class U = T>
|
||||
struct is_nothrow_swappable : std::true_type {};
|
||||
template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
|
||||
#else
|
||||
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
||||
namespace swap_adl_tests {
|
||||
@ -250,8 +249,7 @@
|
||||
struct is_std_swap_noexcept
|
||||
: std::integral_constant<bool,
|
||||
std::is_nothrow_move_constructible<T>::value &&
|
||||
std::is_nothrow_move_assignable<T>::value> {
|
||||
};
|
||||
std::is_nothrow_move_assignable<T>::value> {};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
||||
@ -284,11 +282,12 @@
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
is_swappable<T, U>::value &&
|
||||
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
||||
detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
||||
&&detail::swap_adl_tests::is_adl_swap_noexcept<
|
||||
T, U>::value))> {};
|
||||
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
||||
&&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
||||
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
||||
U>::value))> {
|
||||
};
|
||||
#endif
|
||||
|
||||
// The storage base manages the actual storage, and correctly propagates
|
||||
@ -341,8 +340,7 @@
|
||||
|
||||
// This base class provides some handy member functions which can be used in
|
||||
// further derived classes
|
||||
template <class T>
|
||||
struct optional_operations_base : optional_storage_base<T> {
|
||||
template <class T> struct optional_operations_base : optional_storage_base<T> {
|
||||
using optional_storage_base<T>::optional_storage_base;
|
||||
|
||||
void hard_reset() noexcept {
|
||||
@ -419,8 +417,7 @@
|
||||
#else
|
||||
template <class T, bool = false> struct optional_move_base;
|
||||
#endif
|
||||
template <class T>
|
||||
struct optional_move_base<T, false> : optional_copy_base<T> {
|
||||
template <class T> struct optional_move_base<T, false> : optional_copy_base<T> {
|
||||
using optional_copy_base<T>::optional_copy_base;
|
||||
|
||||
optional_move_base() = default;
|
||||
@ -631,9 +628,6 @@
|
||||
private detail::optional_delete_assign_base<T> {
|
||||
using base = detail::optional_move_assign_base<T>;
|
||||
|
||||
static_assert(
|
||||
!std::is_reference<T>::value,
|
||||
"instantiation of optional with a reference type is ill-formed");
|
||||
static_assert(!std::is_same<T, in_place_t>::value,
|
||||
"instantiation of optional with in_place_t is ill-formed");
|
||||
static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value,
|
||||
@ -723,8 +717,7 @@
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||
template <class F>
|
||||
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&>
|
||||
and_then(F &&f) && {
|
||||
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && {
|
||||
using result = detail::invoke_result_t<F, T &&>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
@ -1100,8 +1093,7 @@
|
||||
/// optional(in_place_t, Args&&... args);
|
||||
template <class... Args>
|
||||
constexpr explicit optional(
|
||||
detail::enable_if_t<std::is_constructible<T, Args...>::value,
|
||||
in_place_t>,
|
||||
detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
|
||||
Args &&... args)
|
||||
: base(in_place, std::forward<Args>(args)...) {}
|
||||
|
||||
@ -1134,9 +1126,9 @@
|
||||
|
||||
/// Converting copy constructor.
|
||||
/// \synopsis template <class U> optional(const optional<U> &rhs);
|
||||
template <class U, detail::enable_from_other<T, U, const U &> * = nullptr,
|
||||
detail::enable_if_t<std::is_convertible<const U &, T>::value> * =
|
||||
nullptr>
|
||||
template <
|
||||
class U, detail::enable_from_other<T, U, const U &> * = nullptr,
|
||||
detail::enable_if_t<std::is_convertible<const U &, T>::value> * = nullptr>
|
||||
optional(const optional<U> &rhs) {
|
||||
this->construct(*rhs);
|
||||
}
|
||||
@ -1329,9 +1321,7 @@
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \exclude
|
||||
constexpr const T &&operator*() const && {
|
||||
return std::move(this->m_value);
|
||||
}
|
||||
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
||||
#endif
|
||||
|
||||
/// \returns whether or not the optional has a value
|
||||
@ -1576,8 +1566,7 @@
|
||||
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
|
||||
/// &rhs);
|
||||
template <class T,
|
||||
detail::enable_if_t<std::is_move_constructible<T>::value> * =
|
||||
nullptr,
|
||||
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
|
||||
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
|
||||
void swap(optional<T> &lhs,
|
||||
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
||||
@ -1602,6 +1591,840 @@
|
||||
template <class T> optional(T)->optional<T>;
|
||||
#endif
|
||||
|
||||
/// An optional object is an object that contains the storage for another
|
||||
/// object and manages the lifetime of this contained object, if any. The
|
||||
/// contained object may be initialized after the optional object has been
|
||||
/// initialized, and may be destroyed before the optional object has been
|
||||
/// destroyed. The initialization state of the contained object is tracked by
|
||||
/// the optional object.
|
||||
template <class T> class optional<T &> {
|
||||
public:
|
||||
// The different versions for C++14 and 11 are needed because deduced return
|
||||
// types are not SFINAE-safe. This provides better support for things like
|
||||
// generic lambdas. C.f.
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
|
||||
#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
|
||||
!defined(TL_OPTIONAL_GCC54)
|
||||
/// \group and_then
|
||||
/// Carries out some operation which returns an optional on the stored
|
||||
/// object if there is one. \requires `std::invoke(std::forward<F>(f),
|
||||
/// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
|
||||
/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
|
||||
/// `std::optional<U>`. The return value is empty if `*this` is empty,
|
||||
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
||||
/// is returned.
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & {
|
||||
using result = detail::invoke_result_t<F, T &>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && {
|
||||
using result = detail::invoke_result_t<F, T &&>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||
template <class F> constexpr auto and_then(F &&f) const & {
|
||||
using result = detail::invoke_result_t<F, const T &>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||
template <class F> constexpr auto and_then(F &&f) const && {
|
||||
using result = detail::invoke_result_t<F, const T &&>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: result(nullopt);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/// \group and_then
|
||||
/// Carries out some operation which returns an optional on the stored
|
||||
/// object if there is one. \requires `std::invoke(std::forward<F>(f),
|
||||
/// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
|
||||
/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
|
||||
/// `std::optional<U>`. The return value is empty if `*this` is empty,
|
||||
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
||||
/// is returned.
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||
template <class F>
|
||||
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) & {
|
||||
using result = detail::invoke_result_t<F, T &>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||
template <class F>
|
||||
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && {
|
||||
using result = detail::invoke_result_t<F, T &&>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||
template <class F>
|
||||
constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & {
|
||||
using result = detail::invoke_result_t<F, const T &>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: result(nullopt);
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group and_then
|
||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||
template <class F>
|
||||
constexpr detail::invoke_result_t<F, const T &&> and_then(F &&f) const && {
|
||||
using result = detail::invoke_result_t<F, const T &&>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: result(nullopt);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
|
||||
!defined(TL_OPTIONAL_GCC54)
|
||||
/// \brief Carries out some operation on the stored object if there is one.
|
||||
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||
/// value())`. Returns a `std::optional<U>`. The return value is empty if
|
||||
/// `*this` is empty, otherwise an `optional<U>` is constructed from the
|
||||
/// return value of `std::invoke(std::forward<F>(f), value())` and is
|
||||
/// returned.
|
||||
///
|
||||
/// \group map
|
||||
/// \synopsis template <class F> constexpr auto map(F &&f) &;
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & {
|
||||
return map_impl(*this, std::forward<F>(f));
|
||||
}
|
||||
|
||||
/// \group map
|
||||
/// \synopsis template <class F> constexpr auto map(F &&f) &&;
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && {
|
||||
return map_impl(std::move(*this), std::forward<F>(f));
|
||||
}
|
||||
|
||||
/// \group map
|
||||
/// \synopsis template <class F> constexpr auto map(F &&f) const&;
|
||||
template <class F> constexpr auto map(F &&f) const & {
|
||||
return map_impl(*this, std::forward<F>(f));
|
||||
}
|
||||
|
||||
/// \group map
|
||||
/// \synopsis template <class F> constexpr auto map(F &&f) const&&;
|
||||
template <class F> constexpr auto map(F &&f) const && {
|
||||
return map_impl(std::move(*this), std::forward<F>(f));
|
||||
}
|
||||
#else
|
||||
/// \brief Carries out some operation on the stored object if there is one.
|
||||
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||
/// value())`. Returns a `std::optional<U>`. The return value is empty if
|
||||
/// `*this` is empty, otherwise an `optional<U>` is constructed from the
|
||||
/// return value of `std::invoke(std::forward<F>(f), value())` and is
|
||||
/// returned.
|
||||
///
|
||||
/// \group map
|
||||
/// \synopsis template <class F> auto map(F &&f) &;
|
||||
template <class F>
|
||||
TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval<optional &>(),
|
||||
std::declval<F &&>()))
|
||||
map(F &&f) & {
|
||||
return map_impl(*this, std::forward<F>(f));
|
||||
}
|
||||
|
||||
/// \group map
|
||||
/// \synopsis template <class F> auto map(F &&f) &&;
|
||||
template <class F>
|
||||
TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval<optional &&>(),
|
||||
std::declval<F &&>()))
|
||||
map(F &&f) && {
|
||||
return map_impl(std::move(*this), std::forward<F>(f));
|
||||
}
|
||||
|
||||
/// \group map
|
||||
/// \synopsis template <class F> auto map(F &&f) const&;
|
||||
template <class F>
|
||||
constexpr decltype(map_impl(std::declval<const optional &>(),
|
||||
std::declval<F &&>()))
|
||||
map(F &&f) const & {
|
||||
return map_impl(*this, std::forward<F>(f));
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group map
|
||||
/// \synopsis template <class F> auto map(F &&f) const&&;
|
||||
template <class F>
|
||||
constexpr decltype(map_impl(std::declval<const optional &&>(),
|
||||
std::declval<F &&>()))
|
||||
map(F &&f) const && {
|
||||
return map_impl(std::move(*this), std::forward<F>(f));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Calls `f` if the optional is empty
|
||||
/// \requires `std::invoke_result_t<F>` must be void or convertible to
|
||||
/// `optional<T>`. \effects If `*this` has a value, returns `*this`.
|
||||
/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns
|
||||
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
|
||||
///
|
||||
/// \group or_else
|
||||
/// \synopsis template <class F> optional<T> or_else (F &&f) &;
|
||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
||||
if (has_value())
|
||||
return *this;
|
||||
|
||||
std::forward<F>(f)();
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/// \exclude
|
||||
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
||||
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
||||
return has_value() ? *this : std::forward<F>(f)();
|
||||
}
|
||||
|
||||
/// \group or_else
|
||||
/// \synopsis template <class F> optional<T> or_else (F &&f) &&;
|
||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||
optional<T> or_else(F &&f) && {
|
||||
if (has_value())
|
||||
return std::move(*this);
|
||||
|
||||
std::forward<F>(f)();
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/// \exclude
|
||||
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
||||
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && {
|
||||
return has_value() ? std::move(*this) : std::forward<F>(f)();
|
||||
}
|
||||
|
||||
/// \group or_else
|
||||
/// \synopsis template <class F> optional<T> or_else (F &&f) const &;
|
||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||
optional<T> or_else(F &&f) const & {
|
||||
if (has_value())
|
||||
return *this;
|
||||
|
||||
std::forward<F>(f)();
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/// \exclude
|
||||
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
||||
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & {
|
||||
return has_value() ? *this : std::forward<F>(f)();
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \exclude
|
||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||
optional<T> or_else(F &&f) const && {
|
||||
if (has_value())
|
||||
return std::move(*this);
|
||||
|
||||
std::forward<F>(f)();
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
/// \exclude
|
||||
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
||||
optional<T> or_else(F &&f) const && {
|
||||
return has_value() ? std::move(*this) : std::forward<F>(f)();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Maps the stored value with `f` if there is one, otherwise returns
|
||||
/// `u`.
|
||||
///
|
||||
/// \details If there is a value stored, then `f` is called with `**this`
|
||||
/// and the value is returned. Otherwise `u` is returned.
|
||||
///
|
||||
/// \group map_or
|
||||
template <class F, class U> U map_or(F &&f, U &&u) & {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: std::forward<U>(u);
|
||||
}
|
||||
|
||||
/// \group map_or
|
||||
template <class F, class U> U map_or(F &&f, U &&u) && {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: std::forward<U>(u);
|
||||
}
|
||||
|
||||
/// \group map_or
|
||||
template <class F, class U> U map_or(F &&f, U &&u) const & {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: std::forward<U>(u);
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group map_or
|
||||
template <class F, class U> U map_or(F &&f, U &&u) const && {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: std::forward<U>(u);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Maps the stored value with `f` if there is one, otherwise calls
|
||||
/// `u` and returns the result.
|
||||
///
|
||||
/// \details If there is a value stored, then `f` is
|
||||
/// called with `**this` and the value is returned. Otherwise
|
||||
/// `std::forward<U>(u)()` is returned.
|
||||
///
|
||||
/// \group map_or_else
|
||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &;
|
||||
template <class F, class U>
|
||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: std::forward<U>(u)();
|
||||
}
|
||||
|
||||
/// \group map_or_else
|
||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
||||
/// &&;
|
||||
template <class F, class U>
|
||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) && {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: std::forward<U>(u)();
|
||||
}
|
||||
|
||||
/// \group map_or_else
|
||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
||||
/// const &;
|
||||
template <class F, class U>
|
||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||
: std::forward<U>(u)();
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group map_or_else
|
||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
||||
/// const &&;
|
||||
template <class F, class U>
|
||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const && {
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||
: std::forward<U>(u)();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \returns `u` if `*this` has a value, otherwise an empty optional.
|
||||
template <class U>
|
||||
constexpr optional<typename std::decay<U>::type> conjunction(U &&u) const {
|
||||
using result = optional<detail::decay_t<U>>;
|
||||
return has_value() ? result{u} : result{nullopt};
|
||||
}
|
||||
|
||||
/// \returns `rhs` if `*this` is empty, otherwise the current value.
|
||||
/// \group disjunction
|
||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & {
|
||||
return has_value() ? *this : rhs;
|
||||
}
|
||||
|
||||
/// \group disjunction
|
||||
constexpr optional disjunction(const optional &rhs) const & {
|
||||
return has_value() ? *this : rhs;
|
||||
}
|
||||
|
||||
/// \group disjunction
|
||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && {
|
||||
return has_value() ? std::move(*this) : rhs;
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group disjunction
|
||||
constexpr optional disjunction(const optional &rhs) const && {
|
||||
return has_value() ? std::move(*this) : rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \group disjunction
|
||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & {
|
||||
return has_value() ? *this : std::move(rhs);
|
||||
}
|
||||
|
||||
/// \group disjunction
|
||||
constexpr optional disjunction(optional &&rhs) const & {
|
||||
return has_value() ? *this : std::move(rhs);
|
||||
}
|
||||
|
||||
/// \group disjunction
|
||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && {
|
||||
return has_value() ? std::move(*this) : std::move(rhs);
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group disjunction
|
||||
constexpr optional disjunction(optional &&rhs) const && {
|
||||
return has_value() ? std::move(*this) : std::move(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Takes the value out of the optional, leaving it empty
|
||||
/// \group take
|
||||
optional take() & {
|
||||
optional ret = *this;
|
||||
reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \group take
|
||||
optional take() const & {
|
||||
optional ret = *this;
|
||||
reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// \group take
|
||||
optional take() && {
|
||||
optional ret = std::move(*this);
|
||||
reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \group take
|
||||
optional take() const && {
|
||||
optional ret = std::move(*this);
|
||||
reset();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
using value_type = T &;
|
||||
|
||||
/// Constructs an optional that does not contain a value.
|
||||
/// \group ctor_empty
|
||||
constexpr optional() noexcept : m_value(nullptr) {}
|
||||
|
||||
/// \group ctor_empty
|
||||
constexpr optional(nullopt_t) noexcept : m_value(nullptr) {}
|
||||
|
||||
/// Copy constructor
|
||||
///
|
||||
/// If `rhs` contains a value, the stored value is direct-initialized with
|
||||
/// it. Otherwise, the constructed optional is empty.
|
||||
TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept = default;
|
||||
|
||||
/// Move constructor
|
||||
///
|
||||
/// If `rhs` contains a value, the stored value is direct-initialized with
|
||||
/// it. Otherwise, the constructed optional is empty.
|
||||
TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default;
|
||||
|
||||
/// Constructs the stored value with `u`.
|
||||
/// \synopsis template <class U=T> constexpr optional(U &&u);
|
||||
template <
|
||||
class U = T,
|
||||
detail::enable_if_t<std::is_convertible<U &&, T &>::value> * = nullptr,
|
||||
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>> * = nullptr>
|
||||
constexpr optional(U &&u) : m_value(std::addressof(u)) {}
|
||||
|
||||
/// \exclude
|
||||
template <class U = T, detail::enable_if_t<
|
||||
!std::is_convertible<U &, T &>::value> * = nullptr>
|
||||
constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {}
|
||||
|
||||
/// \exclude
|
||||
template <class U, detail::enable_if_t<
|
||||
!std::is_convertible<const U &, T>::value> * = nullptr>
|
||||
constexpr explicit optional(const optional<U> &rhs) : optional(*rhs) {}
|
||||
|
||||
/// No-op
|
||||
~optional() = default;
|
||||
|
||||
/// Assignment to empty.
|
||||
///
|
||||
/// Destroys the current value if there is one.
|
||||
optional &operator=(nullopt_t) noexcept {
|
||||
m_value = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Copy assignment.
|
||||
///
|
||||
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
||||
/// value in `*this`.
|
||||
optional &operator=(const optional &rhs) = default;
|
||||
|
||||
/// Assigns the stored value from `u`, destroying the old value if there was
|
||||
/// one.
|
||||
/// \synopsis optional &operator=(U &&u);
|
||||
template <class U = T,
|
||||
detail::enable_if<!detail::is_optional<detail::decay_t<U>>::value>
|
||||
* = nullptr>
|
||||
optional &operator=(U &&u) {
|
||||
m_value = std::addressof(u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Converting copy assignment operator.
|
||||
///
|
||||
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
||||
/// value in `*this`.
|
||||
/// \synopsis optional &operator=(const optional<U> & rhs);
|
||||
template <class U,
|
||||
detail::enable_if<std::is_convertible<U &, T &>::value> * = nullptr>
|
||||
optional &operator=(const optional<U> &rhs) {
|
||||
m_value = std::addressof(rhs.value());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Constructs the value in-place, destroying the current one if there is
|
||||
/// one. \group emplace
|
||||
template <class... Args> T &emplace(Args &&... args) noexcept {
|
||||
static_assert(std::is_constructible<T, Args &&...>::value,
|
||||
"T must be constructible with Args");
|
||||
|
||||
*this = nullopt;
|
||||
this->construct(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Swaps this optional with the other.
|
||||
///
|
||||
/// If neither optionals have a value, nothing happens.
|
||||
/// If both have a value, the values are swapped.
|
||||
/// If one has a value, it is moved to the other and the movee is left
|
||||
/// valueless.
|
||||
void
|
||||
swap(optional &rhs) noexcept {
|
||||
std::swap(m_value, rhs.m_value);
|
||||
}
|
||||
|
||||
/// \returns a pointer to the stored value
|
||||
/// \requires a value is stored
|
||||
/// \group pointer
|
||||
/// \synopsis constexpr const T *operator->() const;
|
||||
constexpr const T *operator->() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/// \group pointer
|
||||
/// \synopsis constexpr T *operator->();
|
||||
TL_OPTIONAL_11_CONSTEXPR T *operator->() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/// \returns the stored value
|
||||
/// \requires a value is stored
|
||||
/// \group deref
|
||||
/// \synopsis constexpr T &operator*();
|
||||
TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return *m_value; }
|
||||
|
||||
/// \group deref
|
||||
/// \synopsis constexpr const T &operator*() const;
|
||||
constexpr const T &operator*() const & { return *m_value; }
|
||||
|
||||
/// \exclude
|
||||
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && {
|
||||
return std::move(*m_value);
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \exclude
|
||||
constexpr const T &&operator*() const && { return std::move(*m_value); }
|
||||
#endif
|
||||
|
||||
/// \returns whether or not the optional has a value
|
||||
/// \group has_value
|
||||
constexpr bool has_value() const noexcept { return m_value != nullptr; }
|
||||
|
||||
/// \group has_value
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return m_value != nullptr;
|
||||
}
|
||||
|
||||
/// \returns the contained value if there is one, otherwise throws
|
||||
/// [bad_optional_access]
|
||||
/// \group value
|
||||
/// synopsis constexpr T &value();
|
||||
TL_OPTIONAL_11_CONSTEXPR T &value() & {
|
||||
if (has_value())
|
||||
return *m_value;
|
||||
throw bad_optional_access();
|
||||
}
|
||||
/// \group value
|
||||
/// \synopsis constexpr const T &value() const;
|
||||
TL_OPTIONAL_11_CONSTEXPR const T &value() const & {
|
||||
if (has_value())
|
||||
return *m_value;
|
||||
throw bad_optional_access();
|
||||
}
|
||||
/// \exclude
|
||||
TL_OPTIONAL_11_CONSTEXPR T &&value() && {
|
||||
if (has_value())
|
||||
return std::move(*m_value);
|
||||
throw bad_optional_access();
|
||||
}
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
/// \exclude
|
||||
constexpr const T &&value() const && {
|
||||
if (has_value())
|
||||
return std::move(*m_value);
|
||||
throw bad_optional_access();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \returns the stored value if there is one, otherwise returns `u`
|
||||
/// \group value_or
|
||||
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() ? **this : static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
/// \group value_or
|
||||
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() ? **this : static_cast<T>(std::forward<U>(u));
|
||||
}
|
||||
|
||||
/// Destroys the stored value if one exists, making the optional empty
|
||||
void reset() noexcept {
|
||||
m_value = nullptr;
|
||||
}
|
||||
}; // namespace tl
|
||||
|
||||
/// \group relop
|
||||
/// \brief Compares two optional objects
|
||||
/// \details If both optionals contain a value, they are compared with `T`s
|
||||
/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
|
||||
/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs`
|
||||
/// is not.
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator==(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return lhs.has_value() == rhs.has_value() &&
|
||||
(!lhs.has_value() || *lhs == *rhs);
|
||||
}
|
||||
/// \group relop
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator!=(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return lhs.has_value() != rhs.has_value() ||
|
||||
(lhs.has_value() && *lhs != *rhs);
|
||||
}
|
||||
/// \group relop
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
|
||||
}
|
||||
/// \group relop
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
|
||||
}
|
||||
/// \group relop
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<=(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
|
||||
}
|
||||
/// \group relop
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>=(const optional<T> &lhs,
|
||||
const optional<U> &rhs) {
|
||||
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
|
||||
}
|
||||
|
||||
/// \group relop_nullopt
|
||||
/// \brief Compares an optional to a `nullopt`
|
||||
/// \details Equivalent to comparing the optional to an empty optional
|
||||
template <class T>
|
||||
inline constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept {
|
||||
return !lhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept {
|
||||
return !rhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept {
|
||||
return lhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept {
|
||||
return rhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator<(const optional<T> &, nullopt_t) noexcept {
|
||||
return false;
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept {
|
||||
return rhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept {
|
||||
return !lhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept {
|
||||
return true;
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept {
|
||||
return lhs.has_value();
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator>(nullopt_t, const optional<T> &) noexcept {
|
||||
return false;
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept {
|
||||
return true;
|
||||
}
|
||||
/// \group relop_nullopt
|
||||
template <class T>
|
||||
inline constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept {
|
||||
return !rhs.has_value();
|
||||
}
|
||||
|
||||
/// \group relop_t
|
||||
/// \brief Compares the optional with a value.
|
||||
/// \details If the optional has a value, it is compared with the other value
|
||||
/// using `T`s relational operators. Otherwise, the optional is considered
|
||||
/// less than the value.
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs == rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs == *rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs != rhs : true;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs != *rhs : true;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs < rhs : true;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs < *rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs <= rhs : true;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs <= *rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs > rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs > *rhs : true;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) {
|
||||
return lhs.has_value() ? *lhs >= rhs : false;
|
||||
}
|
||||
/// \group relop_t
|
||||
template <class T, class U>
|
||||
inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
|
||||
return rhs.has_value() ? lhs >= *rhs : true;
|
||||
}
|
||||
|
||||
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
|
||||
/// &rhs);
|
||||
template <class T,
|
||||
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
|
||||
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
|
||||
void swap(optional<T> &lhs,
|
||||
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline constexpr optional<detail::decay_t<T>> make_optional(T &&v) {
|
||||
return optional<detail::decay_t<T>>(std::forward<T>(v));
|
||||
}
|
||||
template <class T, class... Args>
|
||||
inline constexpr optional<T> make_optional(Args &&... args) {
|
||||
return optional<T>(in_place, std::forward<Args>(args)...);
|
||||
}
|
||||
template <class T, class U, class... Args>
|
||||
inline constexpr optional<T> make_optional(std::initializer_list<U> il,
|
||||
Args &&... args) {
|
||||
return optional<T>(in_place, il, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// \exclude
|
||||
namespace detail {
|
||||
#ifdef TL_OPTIONAL_CX14
|
||||
|
Reference in New Issue
Block a user