mirror of
https://github.com/TartanLlama/optional.git
synced 2025-07-31 02:17:14 +02:00
Fix #1
This commit is contained in:
460
optional.hpp
460
optional.hpp
@ -32,7 +32,12 @@
|
|||||||
#define TL_OPTIONAL_NO_CONSTRR
|
#define TL_OPTIONAL_NO_CONSTRR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || defined(TL_OPTIONAL_GCC49)
|
#if __cplusplus > 201103L
|
||||||
|
#define TL_OPTIONAL_CXX14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \
|
||||||
|
defined(TL_OPTIONAL_GCC49)
|
||||||
/// \exclude
|
/// \exclude
|
||||||
#define TL_OPTIONAL_11_CONSTEXPR
|
#define TL_OPTIONAL_11_CONSTEXPR
|
||||||
#else
|
#else
|
||||||
@ -40,7 +45,6 @@
|
|||||||
#define TL_OPTIONAL_11_CONSTEXPR constexpr
|
#define TL_OPTIONAL_11_CONSTEXPR constexpr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace tl {
|
namespace tl {
|
||||||
/// \brief Used to represent an optional with no data; essentially a bool
|
/// \brief Used to represent an optional with no data; essentially a bool
|
||||||
class monostate {};
|
class monostate {};
|
||||||
@ -118,36 +122,20 @@ using invoke_result = invoke_result_impl<F, void, Us...>;
|
|||||||
template <class F, class... Us>
|
template <class F, class... Us>
|
||||||
using invoke_result_t = typename invoke_result<F, Us...>::type;
|
using invoke_result_t = typename invoke_result<F, Us...>::type;
|
||||||
|
|
||||||
|
|
||||||
// Change void to tl::monostate
|
// Change void to tl::monostate
|
||||||
template <class U>
|
template <class U>
|
||||||
using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;
|
using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;
|
||||||
|
|
||||||
template <class F, class... U> struct get_invoke_optional_ret {
|
template <class F, class U, class = invoke_result_t<F, U>>
|
||||||
using type = invoke_result_t<
|
using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>;
|
||||||
conditional_t<std::is_lvalue_reference<F>::value,
|
|
||||||
typename remove_reference_t<F>::value_type &,
|
|
||||||
typename remove_reference_t<F>::value_type &&>,
|
|
||||||
U...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class F, class... U>
|
|
||||||
using get_invoke_ret = typename conditional_t<is_optional<F>::value,
|
|
||||||
get_invoke_optional_ret<F, U...>,
|
|
||||||
invoke_result<F, U...>>::type;
|
|
||||||
|
|
||||||
template <class F, class U>
|
|
||||||
using get_map_return = optional<fixup_void<get_invoke_ret<F, U>>>;
|
|
||||||
|
|
||||||
// Check if invoking F for some Us returns void
|
// Check if invoking F for some Us returns void
|
||||||
|
template <class F, class = void, class... U> struct returns_void_impl;
|
||||||
template <class F, class... U>
|
template <class F, class... U>
|
||||||
using returns_void = std::is_void<get_invoke_ret<F, U...>>;
|
struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...>
|
||||||
|
: std::is_void<invoke_result_t<F, U...>> {};
|
||||||
template <class T>
|
template <class F, class... U>
|
||||||
using disable_if_optional = enable_if_t<!is_optional<T>::value>;
|
using returns_void = returns_void_impl<F, void, U...>;
|
||||||
|
|
||||||
template <class T>
|
|
||||||
using enable_if_optional = enable_if_t<is_optional<T>::value>;
|
|
||||||
|
|
||||||
template <class T, class... U>
|
template <class T, class... U>
|
||||||
using enable_if_ret_void = enable_if_t<returns_void<T &&, U...>::value>;
|
using enable_if_ret_void = enable_if_t<returns_void<T &&, U...>::value>;
|
||||||
@ -270,10 +258,10 @@ struct is_nothrow_swappable
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
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 {
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept : m_dummy(), m_has_value(false) {}
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
|
||||||
|
: m_dummy(), m_has_value(false) {}
|
||||||
|
|
||||||
template <class... U>
|
template <class... U>
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) noexcept
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) noexcept
|
||||||
@ -296,12 +284,11 @@ struct optional_storage_base {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class T> struct optional_storage_base<T, true> {
|
template <class T> struct optional_storage_base<T, true> {
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
|
||||||
: m_dummy(), m_has_value(false) {}
|
: m_dummy(), m_has_value(false) {}
|
||||||
|
|
||||||
template <class... U>
|
template <class... U>
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t,
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) noexcept
|
||||||
U &&... u) noexcept
|
|
||||||
: m_value(std::forward<U>(u)...), m_has_value(true) {}
|
: m_value(std::forward<U>(u)...), m_has_value(true) {}
|
||||||
|
|
||||||
~optional_storage_base() = default;
|
~optional_storage_base() = default;
|
||||||
@ -314,6 +301,7 @@ template <class T> struct optional_storage_base<T, true> {
|
|||||||
|
|
||||||
bool m_has_value = false;
|
bool m_has_value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// \brief A tag type to represent an empty optional
|
/// \brief A tag type to represent an empty optional
|
||||||
@ -339,18 +327,25 @@ public:
|
|||||||
const char *what() const noexcept { return "Optional has no value"; }
|
const char *what() const noexcept { return "Optional has no value"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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.
|
/// 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 : private detail::optional_storage_base<T> {
|
template <class T> class optional : private detail::optional_storage_base<T> {
|
||||||
using base = detail::optional_storage_base<T>;
|
using base = detail::optional_storage_base<T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// Carries out some operation which returns an optional on the stored object if there is one.
|
/// Carries out some operation which returns an optional on the stored object
|
||||||
/// \requires `std::invoke(std::forward<F>(f), value())` returns a `std::optional<U>` for some `U`.
|
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
|
||||||
/// \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.
|
/// returns a `std::optional<U>` for some `U`. \returns Let `U` be the result
|
||||||
/// \group and_then
|
/// of `std::invoke(std::forward<F>(f), value())`. Returns a
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
/// `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>
|
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>;
|
using result = detail::invoke_result_t<F, T>;
|
||||||
@ -385,7 +380,7 @@ public:
|
|||||||
: result(nullopt);
|
: result(nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
@ -397,187 +392,71 @@ public:
|
|||||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||||
: result(nullopt);
|
: result(nullopt);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TL_OPTIONAL_CXX14
|
||||||
/// \brief Carries out some operation on the stored object if there is one.
|
/// \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.
|
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||||
/// \group map
|
/// value())`. Returns a `std::optional<U>`. The return value is empty if
|
||||||
/// \synopsis template <class F> auto map(F &&f) &;
|
/// `*this` is empty, otherwise an `optional<U>` is constructed from the
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
/// return value of `std::invoke(std::forward<F>(f), value())` and is
|
||||||
detail::disable_if_ret_void<F, T &> * = nullptr>
|
/// returned. \group map \synopsis template <class F> auto map(F &&f) &;
|
||||||
detail::get_map_return<F, T &> map(F &&f) &
|
template <class F> auto map(F &&f) & {
|
||||||
noexcept(noexcept(detail::invoke(std::forward<F>(f),
|
return map_impl(*this, std::forward<F>(f));
|
||||||
std::declval<T &>()))) {
|
|
||||||
using result = detail::get_map_return<F, T &>;
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \exclude
|
template <class F> auto map(F &&f) && {
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
return map_impl(std::move(*this), std::forward<F>(f));
|
||||||
detail::enable_if_ret_void<F, T &> * = nullptr>
|
|
||||||
detail::get_map_return<F, T &> map(F &&f) & {
|
|
||||||
if (!has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(std::forward<F>(f), **this);
|
|
||||||
return monostate{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \exclude
|
template <class F> auto map(F &&f) const & {
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
return map_impl(*this, std::forward<F>(f));
|
||||||
detail::disable_if_ret_void<F, T &> * = nullptr>
|
|
||||||
detail::get_map_return<F, T &> map(F &&f) & {
|
|
||||||
using result = detail::get_map_return<F, T &>;
|
|
||||||
return (f.has_value() && has_value())
|
|
||||||
? detail::invoke(*std::forward<F>(f), **this)
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \exclude
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
template <class F> auto map(F &&f) const && {
|
||||||
detail::enable_if_ret_void<F, T &> * = nullptr>
|
return map_impl(std::move(*this), std::forward<F>(f));
|
||||||
detail::get_map_return<F, T &> map(F &&f) & {
|
}
|
||||||
if (!f.has_value() || !has_value())
|
#endif
|
||||||
return nullopt;
|
#else
|
||||||
|
/// \brief Carries out some operation on the stored object if there is one.
|
||||||
detail::invoke(*std::forward<F>(f), **this);
|
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
|
||||||
return monostate{};
|
/// 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>
|
||||||
|
decltype(map_impl(std::declval<optional &>(), std::declval<F &&>()))
|
||||||
|
map(F &&f) & {
|
||||||
|
return map_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group map
|
template <class F>
|
||||||
/// \synopsis template <class F> auto map(F &&f) &&;
|
decltype(map_impl(std::declval<optional &&>(), std::declval<F &&>()))
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
map(F &&f) && {
|
||||||
detail::disable_if_ret_void<F, T &&> * = nullptr>
|
return map_impl(std::move(*this), std::forward<F>(f));
|
||||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
|
||||||
using result = detail::get_map_return<F, T &&>;
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \exclude
|
template <class F>
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
decltype(map_impl(std::declval<const optional &>(), std::declval<F &&>()))
|
||||||
detail::enable_if_ret_void<F, T &&> * = nullptr>
|
map(F &&f) const & {
|
||||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
return map_impl(*this, std::forward<F>(f));
|
||||||
if (!has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(std::forward<F>(f), std::move(**this));
|
|
||||||
return monostate{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \exclude
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
template <class F>
|
||||||
detail::disable_if_ret_void<F, T &&> * = nullptr>
|
decltype(map_impl(std::declval<const optional &&>(), std::declval<F &&>()))
|
||||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
map(F &&f) const && {
|
||||||
using result = detail::get_map_return<F, T &&>;
|
return map_impl(std::move(*this), std::forward<F>(f));
|
||||||
return (f.has_value() && has_value())
|
|
||||||
? detail::invoke(*std::forward<F>(f), std::move(**this))
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/// \exclude
|
#endif
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
|
||||||
detail::enable_if_ret_void<F, T &&> * = nullptr>
|
|
||||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
|
||||||
if (!f.has_value() || !has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(*std::forward<F>(f), std::move(**this));
|
|
||||||
return monostate{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \group map
|
|
||||||
/// \synopsis template <class F> auto map(F &&f) const &;
|
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
|
||||||
detail::disable_if_ret_void<F, T const &> * = nullptr>
|
|
||||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
|
||||||
using result = detail::get_map_return<F, T const &>;
|
|
||||||
return this->has_value()
|
|
||||||
? result(detail::invoke(std::forward<F>(f), **this))
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
|
||||||
detail::enable_if_ret_void<F, T const &> * = nullptr>
|
|
||||||
detail::get_map_return<F, T const &> map(F &&f) const & {
|
|
||||||
if (!has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(std::forward<F>(f), **this);
|
|
||||||
return monostate{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
|
||||||
detail::disable_if_ret_void<F, T const &> * = nullptr>
|
|
||||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
|
||||||
using result = detail::get_map_return<F, const T &>;
|
|
||||||
return (f.has_value() && has_value())
|
|
||||||
? detail::invoke(*std::forward<F>(f), **this)
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
|
||||||
detail::enable_if_ret_void<F, T const &> * = nullptr>
|
|
||||||
detail::get_map_return<F, T const &> map(F &&f) const & {
|
|
||||||
if (!f.has_value() || !has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(*std::forward<F>(f), **this);
|
|
||||||
return monostate{};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
|
||||||
/// \group map
|
|
||||||
/// \synopsis template <class F> auto map(F &&f) const &&;
|
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
|
||||||
detail::disable_if_ret_void<F, T const &&> * = nullptr>
|
|
||||||
constexpr detail::get_map_return<F, T const &&> map(F &&f) const && {
|
|
||||||
using result = detail::get_map_return<F, const T &&>;
|
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
|
||||||
detail::enable_if_ret_void<F, T const &&> * = nullptr>
|
|
||||||
detail::get_map_return<F, T const &&> map(F &&f) const && {
|
|
||||||
if (!has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(std::forward<F>(f), std::move(**this));
|
|
||||||
return monostate{};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
|
||||||
detail::disable_if_ret_void<F, T const &&> * = nullptr>
|
|
||||||
constexpr detail::get_map_return<F, T const &&> map(F &&f) const && {
|
|
||||||
using result = detail::get_map_return<F, const T &&>;
|
|
||||||
return (f.has_value() && has_value())
|
|
||||||
? detail::invoke(*std::forward<F>(f), std::move(**this))
|
|
||||||
: result(nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
|
||||||
detail::enable_if_ret_void<F, T const &&> * = nullptr>
|
|
||||||
detail::get_map_return<F, T &> map(F &&f) const && {
|
|
||||||
if (!f.has_value() || !has_value())
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
detail::invoke(*std::forward<F>(f), std::move(**this));
|
|
||||||
return monostate{};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// \brief Calls `f` if the optional is empty
|
/// \brief Calls `f` if the optional is empty
|
||||||
/// \requires `std::invoke_result_t<F>` must be void or convertible to `optional<T>`.
|
/// \requires `std::invoke_result_t<F>` must be void or convertible to
|
||||||
/// \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)()`.
|
/// `optional<T>`. \effects If `*this` has a value, returns `*this`.
|
||||||
/// \group or_else
|
/// 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) &;
|
/// \synopsis template <class F> optional<T> or_else (F &&f) &;
|
||||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||||
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
||||||
@ -628,7 +507,7 @@ public:
|
|||||||
return has_value() ? *this : std::forward<F>(f)();
|
return has_value() ? *this : std::forward<F>(f)();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \exclude
|
/// \exclude
|
||||||
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
||||||
optional<T> or_else(F &&f) const && {
|
optional<T> or_else(F &&f) const && {
|
||||||
@ -644,12 +523,11 @@ public:
|
|||||||
optional<T> or_else(F &&f) const && {
|
optional<T> or_else(F &&f) const && {
|
||||||
return has_value() ? std::move(*this) : std::forward<F>(f)();
|
return has_value() ? std::move(*this) : std::forward<F>(f)();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \brief Maps the stored value with `f` if there is one, otherwise returns `u`
|
/// \brief Maps the stored value with `f` if there is one, otherwise returns
|
||||||
/// \details If there is a value stored, then `f` is called with `**this` and the value is returned.
|
/// `u` \details If there is a value stored, then `f` is called with `**this`
|
||||||
/// Otherwise `u` is returned.
|
/// and the value is returned. Otherwise `u` is returned. \group map_or
|
||||||
/// \group map_or
|
|
||||||
template <class F, class U> U map_or(F &&f, U &&u) & {
|
template <class F, class U> U map_or(F &&f, U &&u) & {
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||||
: std::forward<U>(u);
|
: std::forward<U>(u);
|
||||||
@ -667,19 +545,19 @@ public:
|
|||||||
: std::forward<U>(u);
|
: std::forward<U>(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group map_or
|
/// \group map_or
|
||||||
template <class F, class U> U map_or(F &&f, U &&u) const && {
|
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))
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||||
: std::forward<U>(u);
|
: std::forward<U>(u);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \brief Maps the stored value with `f` if there is one, otherwise calls `u` and returns the result.
|
/// \brief Maps the stored value with `f` if there is one, otherwise calls `u`
|
||||||
/// \details If there is a value stored, then `f` is called with `**this` and the value is returned.
|
/// and returns the result. \details If there is a value stored, then `f` is
|
||||||
/// Otherwise `std::forward<U>(u)()` is returned.
|
/// called with `**this` and the value is returned. Otherwise
|
||||||
/// \group map_or_else
|
/// `std::forward<U>(u)()` is returned. \group map_or_else \synopsis template
|
||||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &;
|
/// <class F, class U>\nauto map_or_else(F &&f, U &&u) &;
|
||||||
template <class F, class U>
|
template <class F, class U>
|
||||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & {
|
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & {
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||||
@ -695,74 +573,76 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \group map_or_else
|
/// \group map_or_else
|
||||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) const &;
|
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
||||||
|
/// const &;
|
||||||
template <class F, class U>
|
template <class F, class U>
|
||||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & {
|
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & {
|
||||||
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
||||||
: std::forward<U>(u)();
|
: std::forward<U>(u)();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group map_or_else
|
/// \group map_or_else
|
||||||
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) const &&;
|
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
||||||
|
/// const &&;
|
||||||
template <class F, class U>
|
template <class F, class U>
|
||||||
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const && {
|
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))
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
||||||
: std::forward<U>(u)();
|
: std::forward<U>(u)();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \returns `u` if `*this` has a value, otherwise an empty optional.
|
/// \returns `u` if `*this` has a value, otherwise an empty optional.
|
||||||
template <class U>
|
template <class U>
|
||||||
constexpr optional<typename std::decay<U>::type> conjunction (U &&u) const {
|
constexpr optional<typename std::decay<U>::type> conjunction(U &&u) const {
|
||||||
using result = optional<detail::decay_t<U>>;
|
using result = optional<detail::decay_t<U>>;
|
||||||
return has_value() ? result{u} : result{nullopt};
|
return has_value() ? result{u} : result{nullopt};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns `rhs` if `*this` is empty, otherwise the current value.
|
/// \returns `rhs` if `*this` is empty, otherwise the current value.
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction (const optional &rhs) & {
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & {
|
||||||
return has_value() ? *this : rhs;
|
return has_value() ? *this : rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
constexpr optional disjunction (const optional &rhs) const & {
|
constexpr optional disjunction(const optional &rhs) const & {
|
||||||
return has_value() ? *this : rhs;
|
return has_value() ? *this : rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction (const optional &rhs) && {
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && {
|
||||||
return has_value() ? std::move(*this) : rhs;
|
return has_value() ? std::move(*this) : rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
constexpr optional disjunction (const optional &rhs) const && {
|
constexpr optional disjunction(const optional &rhs) const && {
|
||||||
return has_value() ? std::move(*this) : rhs;
|
return has_value() ? std::move(*this) : rhs;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction (optional &&rhs) & {
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & {
|
||||||
return has_value() ? *this : std::move(rhs);
|
return has_value() ? *this : std::move(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
constexpr optional disjunction (optional &&rhs) const & {
|
constexpr optional disjunction(optional &&rhs) const & {
|
||||||
return has_value() ? *this : std::move(rhs);
|
return has_value() ? *this : std::move(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
TL_OPTIONAL_11_CONSTEXPR optional disjunction (optional &&rhs) && {
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && {
|
||||||
return has_value() ? std::move(*this) : std::move(rhs);
|
return has_value() ? std::move(*this) : std::move(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group disjunction
|
/// \group disjunction
|
||||||
constexpr optional disjunction (optional &&rhs) const && {
|
constexpr optional disjunction(optional &&rhs) const && {
|
||||||
return has_value() ? std::move(*this) : std::move(rhs);
|
return has_value() ? std::move(*this) : std::move(rhs);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Takes the value out of the optional, leaving it empty
|
/// Takes the value out of the optional, leaving it empty
|
||||||
/// \group take
|
/// \group take
|
||||||
@ -786,14 +666,14 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \group take
|
/// \group take
|
||||||
optional take() const && {
|
optional take() const && {
|
||||||
optional ret = std::move(*this);
|
optional ret = std::move(*this);
|
||||||
reset();
|
reset();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
@ -828,10 +708,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Constructs the stored value in-place using the given arguments.
|
/// Constructs the stored value in-place using the given arguments.
|
||||||
/// \group in_place
|
/// \group in_place
|
||||||
/// \synopsis template <class... Args> constexpr explicit optional(in_place_t, Args&&... args);
|
/// \synopsis template <class... Args> constexpr explicit optional(in_place_t,
|
||||||
|
/// Args&&... args);
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
constexpr explicit optional(
|
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>,
|
||||||
@ -839,7 +719,8 @@ public:
|
|||||||
: base(in_place, std::forward<Args>(args)...) {}
|
: base(in_place, std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
/// \group in_place
|
/// \group in_place
|
||||||
/// \synopsis template <class U, class... Args>\nconstexpr explicit optional(in_place_t, std::initializer_list<U>&, Args&&... args);
|
/// \synopsis template <class U, class... Args>\nconstexpr explicit
|
||||||
|
/// optional(in_place_t, std::initializer_list<U>&, Args&&... args);
|
||||||
template <class U, class... Args>
|
template <class U, class... Args>
|
||||||
TL_OPTIONAL_11_CONSTEXPR explicit optional(
|
TL_OPTIONAL_11_CONSTEXPR explicit optional(
|
||||||
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &,
|
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &,
|
||||||
@ -921,7 +802,8 @@ public:
|
|||||||
// TODO conditionally delete, check exception guarantee
|
// TODO conditionally delete, check exception guarantee
|
||||||
/// Copy assignment.
|
/// Copy assignment.
|
||||||
///
|
///
|
||||||
/// Copies the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
|
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
||||||
|
/// value in `*this`.
|
||||||
optional &operator=(const optional &rhs) {
|
optional &operator=(const optional &rhs) {
|
||||||
if (has_value()) {
|
if (has_value()) {
|
||||||
if (rhs.has_value()) {
|
if (rhs.has_value()) {
|
||||||
@ -943,7 +825,8 @@ public:
|
|||||||
// TODO conditionally delete, check exception guarantee
|
// TODO conditionally delete, check exception guarantee
|
||||||
/// Move assignment.
|
/// Move assignment.
|
||||||
///
|
///
|
||||||
/// Moves the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
|
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
|
||||||
|
/// value in `*this`.
|
||||||
optional &operator=(optional &&rhs) noexcept(
|
optional &operator=(optional &&rhs) noexcept(
|
||||||
std::is_nothrow_move_assignable<T>::value
|
std::is_nothrow_move_assignable<T>::value
|
||||||
&&std::is_nothrow_move_constructible<T>::value) {
|
&&std::is_nothrow_move_constructible<T>::value) {
|
||||||
@ -965,8 +848,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO conditionally delete, check exception guarantee
|
// TODO conditionally delete, check exception guarantee
|
||||||
/// Assigns the stored value from `u`, destroying the old value if there was one.
|
/// Assigns the stored value from `u`, destroying the old value if there was
|
||||||
/// \synopsis optional &operator=(U &&u);
|
/// one. \synopsis optional &operator=(U &&u);
|
||||||
template <class U = T, detail::enable_assign_forward<T, U> * = nullptr>
|
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()) {
|
||||||
@ -982,8 +865,8 @@ public:
|
|||||||
// TODO check exception guarantee
|
// TODO check exception guarantee
|
||||||
/// Converting copy assignment operator.
|
/// Converting copy assignment operator.
|
||||||
///
|
///
|
||||||
/// Copies the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
|
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
||||||
/// \synopsis optional &operator=(const optional<U> & rhs);
|
/// value in `*this`. \synopsis optional &operator=(const optional<U> & rhs);
|
||||||
template <class U,
|
template <class U,
|
||||||
detail::enable_assign_from_other<T, U, const U &> * = nullptr>
|
detail::enable_assign_from_other<T, U, const U &> * = nullptr>
|
||||||
optional &operator=(const optional<U> &rhs) {
|
optional &operator=(const optional<U> &rhs) {
|
||||||
@ -1007,8 +890,8 @@ public:
|
|||||||
// TODO check exception guarantee
|
// TODO check exception guarantee
|
||||||
/// Converting move assignment operator.
|
/// Converting move assignment operator.
|
||||||
///
|
///
|
||||||
/// Moves the value from `rhs` if there is one. Otherwise resets the stored value in `*this`.
|
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
|
||||||
/// \synopsis optional &operator=(optional<U> && rhs);
|
/// value in `*this`. \synopsis optional &operator=(optional<U> && rhs);
|
||||||
template <class U, detail::enable_assign_from_other<T, U, U> * = nullptr>
|
template <class U, detail::enable_assign_from_other<T, U, U> * = nullptr>
|
||||||
optional &operator=(optional<U> &&rhs) {
|
optional &operator=(optional<U> &&rhs) {
|
||||||
if (has_value()) {
|
if (has_value()) {
|
||||||
@ -1039,7 +922,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// \group emplace
|
/// \group emplace
|
||||||
/// \synopsis template <class U, class... Args>\nT& emplace(std::initializer_list<U> il, Args &&... args);
|
/// \synopsis template <class U, class... Args>\nT&
|
||||||
|
/// emplace(std::initializer_list<U> il, Args &&... args);
|
||||||
template <class U, class... Args>
|
template <class U, class... Args>
|
||||||
detail::enable_if_t<
|
detail::enable_if_t<
|
||||||
std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value,
|
std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value,
|
||||||
@ -1053,7 +937,8 @@ public:
|
|||||||
///
|
///
|
||||||
/// If neither optionals have a value, nothing happens.
|
/// If neither optionals have a value, nothing happens.
|
||||||
/// If both have a value, the values are swapped.
|
/// 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.
|
/// If one has a value, it is moved to the other and the movee is left
|
||||||
|
/// valueless.
|
||||||
void
|
void
|
||||||
swap(optional &rhs) noexcept(std::is_nothrow_move_constructible<T>::value
|
swap(optional &rhs) noexcept(std::is_nothrow_move_constructible<T>::value
|
||||||
&&detail::is_nothrow_swappable<T>::value) {
|
&&detail::is_nothrow_swappable<T>::value) {
|
||||||
@ -1100,10 +985,10 @@ public:
|
|||||||
return std::move(this->m_value);
|
return std::move(this->m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \exclude
|
/// \exclude
|
||||||
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \returns whether or not the optional has a value
|
/// \returns whether or not the optional has a value
|
||||||
/// \group has_value
|
/// \group has_value
|
||||||
@ -1114,9 +999,8 @@ public:
|
|||||||
return this->m_has_value;
|
return this->m_has_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns the contained value if there is one, otherwise throws [bad_optional_access]
|
/// \returns the contained value if there is one, otherwise throws
|
||||||
/// \group value
|
/// [bad_optional_access] \group value \synopsis constexpr T &value();
|
||||||
/// \synopsis constexpr T &value();
|
|
||||||
TL_OPTIONAL_11_CONSTEXPR T &value() & {
|
TL_OPTIONAL_11_CONSTEXPR T &value() & {
|
||||||
if (has_value())
|
if (has_value())
|
||||||
return this->m_value;
|
return this->m_value;
|
||||||
@ -1136,14 +1020,14 @@ public:
|
|||||||
throw bad_optional_access();
|
throw bad_optional_access();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \exclude
|
/// \exclude
|
||||||
constexpr const T &&value() const && {
|
constexpr const T &&value() const && {
|
||||||
if (has_value())
|
if (has_value())
|
||||||
return std::move(this->m_value);
|
return std::move(this->m_value);
|
||||||
throw bad_optional_access();
|
throw bad_optional_access();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \returns the stored value if there is one, otherwise returns `u`
|
/// \returns the stored value if there is one, otherwise returns `u`
|
||||||
/// \group value_or
|
/// \group value_or
|
||||||
@ -1169,15 +1053,14 @@ public:
|
|||||||
this->m_has_value = false;
|
this->m_has_value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \group relop
|
/// \group relop
|
||||||
/// \brief Compares two optional objects
|
/// \brief Compares two optional objects
|
||||||
/// \details If both optionals contain a value, they are compared with `T`s relational operators.
|
/// \details If both optionals contain a value, they are compared with `T`s
|
||||||
/// Otherwise `lhs` and `rhs` are equal only if they are both empty, and `lhs` is less than `rhs`
|
/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
|
||||||
/// only if `rhs` is empty and `lhs` is not.
|
/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` is
|
||||||
|
/// not.
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator==(const optional<T> &lhs,
|
inline constexpr bool operator==(const optional<T> &lhs,
|
||||||
const optional<U> &rhs) {
|
const optional<U> &rhs) {
|
||||||
@ -1279,11 +1162,11 @@ inline constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept {
|
|||||||
return !rhs.has_value();
|
return !rhs.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \group relop_t
|
/// \group relop_t
|
||||||
/// \brief Compares the optional with a value.
|
/// \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.
|
/// \details If the optional has a value, it is compared with the other value
|
||||||
/// Otherwise, the optional is considered less than the value.
|
/// using `T`s relational operators. Otherwise, the optional is considered less
|
||||||
|
/// than the value.
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
|
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;
|
||||||
@ -1371,6 +1254,59 @@ inline constexpr optional<T> make_optional(std::initializer_list<U> il,
|
|||||||
template <class T> optional(T)->optional<T>;
|
template <class T> optional(T)->optional<T>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// \exclude
|
||||||
|
namespace detail {
|
||||||
|
#ifdef TL_OPTIONAL_CX14
|
||||||
|
template <class Opt, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Opt>())),
|
||||||
|
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
||||||
|
auto map_impl(Opt &&opt, F &&f) {
|
||||||
|
return opt.has_value()
|
||||||
|
? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt))
|
||||||
|
: optional<Ret>(nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Opt, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Opt>())),
|
||||||
|
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||||
|
auto map_impl(Opt &&opt, F &&f) {
|
||||||
|
if (opt.has_value()) {
|
||||||
|
detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
|
||||||
|
return monostate{};
|
||||||
|
}
|
||||||
|
|
||||||
|
return optional<Ret>(nullopt);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <class Opt, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Opt>())),
|
||||||
|
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
||||||
|
|
||||||
|
auto map_impl(Opt &&opt, F &&f) -> optional<Ret> {
|
||||||
|
return opt.has_value()
|
||||||
|
? detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt))
|
||||||
|
: optional<Ret>(nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Opt, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
*std::declval<Opt>())),
|
||||||
|
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||||
|
|
||||||
|
auto map_impl(Opt &&opt, F &&f) -> optional<monostate> {
|
||||||
|
if (opt.has_value()) {
|
||||||
|
detail::invoke(std::forward<F>(f), *std::forward<Opt>(opt));
|
||||||
|
return monostate{};
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace tl
|
} // namespace tl
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -12,342 +12,272 @@ constexpr int get_int(int) { return 42; }
|
|||||||
TL_OPTIONAL_11_CONSTEXPR tl::optional<int> get_opt_int(int) { return 42; }
|
TL_OPTIONAL_11_CONSTEXPR tl::optional<int> get_opt_int(int) { return 42; }
|
||||||
|
|
||||||
// What is Clang Format up to?!
|
// What is Clang Format up to?!
|
||||||
TEST_CASE("Monadic operations",
|
TEST_CASE("Monadic operations", "[monadic]") {
|
||||||
"[monadic]"){SECTION("map"){// lhs is empty
|
SECTION("map") { // lhs is empty
|
||||||
tl::optional<int> o1;
|
tl::optional<int> o1;
|
||||||
auto o1r = o1.map([](int i) { return i + 2; });
|
auto o1r = o1.map([](int i) { return i + 2; });
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<int>>::value));
|
STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<int>>::value));
|
||||||
REQUIRE(!o1r);
|
REQUIRE(!o1r);
|
||||||
|
|
||||||
// lhs has value
|
// lhs has value
|
||||||
tl::optional<int> o2 = 40;
|
tl::optional<int> o2 = 40;
|
||||||
auto o2r = o2.map([](int i) { return i + 2; });
|
auto o2r = o2.map([](int i) { return i + 2; });
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<int>>::value));
|
STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<int>>::value));
|
||||||
REQUIRE(o2r.value() == 42);
|
REQUIRE(o2r.value() == 42);
|
||||||
|
|
||||||
struct rval_call_map {
|
struct rval_call_map {
|
||||||
double operator()(int) && { return 42.0; };
|
double operator()(int) && { return 42.0; };
|
||||||
};
|
|
||||||
|
|
||||||
// ensure that function object is forwarded
|
|
||||||
tl::optional<int> o3 = 42;
|
|
||||||
auto o3r = o3.map(rval_call_map{});
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<double>>::value));
|
|
||||||
REQUIRE(o3r.value() == 42);
|
|
||||||
|
|
||||||
// ensure that lhs is forwarded
|
|
||||||
tl::optional<int> o4 = 40;
|
|
||||||
auto o4r = std::move(o4).map([](int &&i) { return i + 2; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<int>>::value));
|
|
||||||
REQUIRE(o4r.value() == 42);
|
|
||||||
|
|
||||||
// ensure that lhs is const-propagated
|
|
||||||
const tl::optional<int> o5 = 40;
|
|
||||||
auto o5r = o5.map([](const int &i) { return i + 2; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<int>>::value));
|
|
||||||
REQUIRE(o5r.value() == 42);
|
|
||||||
|
|
||||||
// test applicative functor
|
|
||||||
tl::optional<int> o6 = 40;
|
|
||||||
auto f6 = tl::make_optional([](const int &i) { return i + 2; });
|
|
||||||
auto o6r = o6.map(f6);
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o6r), tl::optional<int>>::value));
|
|
||||||
REQUIRE(o6r.value() == 42);
|
|
||||||
|
|
||||||
// test void return
|
|
||||||
tl::optional<int> o7 = 40;
|
|
||||||
auto f7 = tl::make_optional([](const int &i) { return; });
|
|
||||||
auto o7r = o7.map(f7);
|
|
||||||
STATIC_REQUIRE(
|
|
||||||
(std::is_same<decltype(o7r), tl::optional<tl::monostate>>::value));
|
|
||||||
REQUIRE(o6r.has_value());
|
|
||||||
|
|
||||||
// test each overload in turn
|
|
||||||
tl::optional<int> o8 = 42;
|
|
||||||
auto o8r = o8.map([](int) { return 42; });
|
|
||||||
REQUIRE(*o8r == 42);
|
|
||||||
|
|
||||||
tl::optional<int> o9 = 42;
|
|
||||||
auto o9r = o9.map([](int) { return; });
|
|
||||||
REQUIRE(o9r);
|
|
||||||
|
|
||||||
tl::optional<int> o10 = 42;
|
|
||||||
auto o10r = o10.map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(*o10r == 42);
|
|
||||||
|
|
||||||
tl::optional<int> o11 = 42;
|
|
||||||
auto o11r = o11.map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(o11r);
|
|
||||||
|
|
||||||
tl::optional<int> o12 = 42;
|
|
||||||
auto o12r = std::move(o12).map([](int) { return 42; });
|
|
||||||
REQUIRE(*o12r == 42);
|
|
||||||
|
|
||||||
tl::optional<int> o13 = 42;
|
|
||||||
auto o13r = std::move(o13).map([](int) { return; });
|
|
||||||
REQUIRE(o13r);
|
|
||||||
|
|
||||||
tl::optional<int> o14 = 42;
|
|
||||||
auto o14r = std::move(o14).map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(*o14r == 42);
|
|
||||||
|
|
||||||
tl::optional<int> o15 = 42;
|
|
||||||
auto o15r = std::move(o15).map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(o15r);
|
|
||||||
|
|
||||||
const tl::optional<int> o16 = 42;
|
|
||||||
auto o16r = o16.map([](int) { return 42; });
|
|
||||||
REQUIRE(*o16r == 42);
|
|
||||||
|
|
||||||
const tl::optional<int> o17 = 42;
|
|
||||||
auto o17r = o17.map([](int) { return; });
|
|
||||||
REQUIRE(o17r);
|
|
||||||
|
|
||||||
const tl::optional<int> o18 = 42;
|
|
||||||
auto o18r = o18.map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(*o18r == 42);
|
|
||||||
|
|
||||||
const tl::optional<int> o19 = 42;
|
|
||||||
auto o19r = o19.map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(o19r);
|
|
||||||
|
|
||||||
const tl::optional<int> o20 = 42;
|
|
||||||
auto o20r = std::move(o20).map([](int) { return 42; });
|
|
||||||
REQUIRE(*o20r == 42);
|
|
||||||
|
|
||||||
const tl::optional<int> o21 = 42;
|
|
||||||
auto o21r = std::move(o21).map([](int) { return; });
|
|
||||||
REQUIRE(o21r);
|
|
||||||
|
|
||||||
const tl::optional<int> o22 = 42;
|
|
||||||
auto o22r = std::move(o22).map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(*o22r == 42);
|
|
||||||
|
|
||||||
const tl::optional<int> o23 = 42;
|
|
||||||
auto o23r = std::move(o23).map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(o23r);
|
|
||||||
|
|
||||||
tl::optional<int> o24 = tl::nullopt;
|
|
||||||
auto o24r = o24.map([](int) { return 42; });
|
|
||||||
REQUIRE(!o24r);
|
|
||||||
|
|
||||||
tl::optional<int> o25 = tl::nullopt;
|
|
||||||
auto o25r = o25.map([](int) { return; });
|
|
||||||
REQUIRE(!o25r);
|
|
||||||
|
|
||||||
tl::optional<int> o26 = tl::nullopt;
|
|
||||||
auto o26r = o26.map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(!o26r);
|
|
||||||
|
|
||||||
tl::optional<int> o27 = tl::nullopt;
|
|
||||||
auto o27r = o27.map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(!o27r);
|
|
||||||
|
|
||||||
tl::optional<int> o28 = tl::nullopt;
|
|
||||||
auto o28r = std::move(o28).map([](int) { return 42; });
|
|
||||||
REQUIRE(!o28r);
|
|
||||||
|
|
||||||
tl::optional<int> o29 = tl::nullopt;
|
|
||||||
auto o29r = std::move(o29).map([](int) { return; });
|
|
||||||
REQUIRE(!o29r);
|
|
||||||
|
|
||||||
tl::optional<int> o30 = tl::nullopt;
|
|
||||||
auto o30r = std::move(o30).map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(!o30r);
|
|
||||||
|
|
||||||
tl::optional<int> o31 = tl::nullopt;
|
|
||||||
auto o31r = std::move(o31).map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(!o31r);
|
|
||||||
|
|
||||||
const tl::optional<int> o32 = tl::nullopt;
|
|
||||||
auto o32r = o32.map([](int) { return 42; });
|
|
||||||
REQUIRE(!o32r);
|
|
||||||
|
|
||||||
const tl::optional<int> o33 = tl::nullopt;
|
|
||||||
auto o33r = o33.map([](int) { return; });
|
|
||||||
REQUIRE(!o33r);
|
|
||||||
|
|
||||||
const tl::optional<int> o34 = tl::nullopt;
|
|
||||||
auto o34r = o34.map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(!o34r);
|
|
||||||
|
|
||||||
const tl::optional<int> o35 = tl::nullopt;
|
|
||||||
auto o35r = o35.map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(!o35r);
|
|
||||||
|
|
||||||
const tl::optional<int> o36 = tl::nullopt;
|
|
||||||
auto o36r = std::move(o36).map([](int) { return 42; });
|
|
||||||
REQUIRE(!o36r);
|
|
||||||
|
|
||||||
const tl::optional<int> o37 = tl::nullopt;
|
|
||||||
auto o37r = std::move(o37).map([](int) { return; });
|
|
||||||
REQUIRE(!o37r);
|
|
||||||
|
|
||||||
const tl::optional<int> o38 = tl::nullopt;
|
|
||||||
auto o38r = std::move(o38).map(tl::make_optional([](int) { return 42; }));
|
|
||||||
REQUIRE(!o38r);
|
|
||||||
|
|
||||||
const tl::optional<int> o39 = tl::nullopt;
|
|
||||||
auto o39r = std::move(o39).map(tl::make_optional([](int) { return; }));
|
|
||||||
REQUIRE(!o39r);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("map constexpr") {
|
|
||||||
#if !defined(_MSC_VER) && !defined(TL_OPTIONAL_GCC49)
|
|
||||||
// test each overload in turn
|
|
||||||
constexpr tl::optional<int> o16 = 42;
|
|
||||||
constexpr auto o16r = o16.map(get_int);
|
|
||||||
STATIC_REQUIRE(*o16r == 42);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o18 = 42;
|
|
||||||
constexpr auto opt_int = tl::make_optional(get_int);
|
|
||||||
constexpr auto o18r = o18.map(opt_int);
|
|
||||||
STATIC_REQUIRE(*o18r == 42);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o20 = 42;
|
|
||||||
constexpr auto o20r = std::move(o20).map(get_int);
|
|
||||||
STATIC_REQUIRE(*o20r == 42);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o22 = 42;
|
|
||||||
constexpr auto o22r = std::move(o22).map(opt_int);
|
|
||||||
STATIC_REQUIRE(*o22r == 42);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o32 = tl::nullopt;
|
|
||||||
constexpr auto o32r = o32.map(get_int);
|
|
||||||
STATIC_REQUIRE(!o32r);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o34 = tl::nullopt;
|
|
||||||
constexpr auto o34r = o34.map(opt_int);
|
|
||||||
STATIC_REQUIRE(!o34r);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o36 = tl::nullopt;
|
|
||||||
constexpr auto o36r = std::move(o36).map(get_int);
|
|
||||||
STATIC_REQUIRE(!o36r);
|
|
||||||
|
|
||||||
constexpr tl::optional<int> o38 = tl::nullopt;
|
|
||||||
constexpr auto o38r = std::move(o38).map(opt_int);
|
|
||||||
STATIC_REQUIRE(!o38r);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("and_then") {
|
|
||||||
|
|
||||||
// lhs is empty
|
|
||||||
tl::optional<int> o1;
|
|
||||||
auto o1r = o1.and_then([](int i) { return tl::optional<float>{42}; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<float>>::value));
|
|
||||||
REQUIRE(!o1r);
|
|
||||||
|
|
||||||
// lhs has value
|
|
||||||
tl::optional<int> o2 = 12;
|
|
||||||
auto o2r = o2.and_then([](int i) { return tl::optional<float>{42}; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<float>>::value));
|
|
||||||
REQUIRE(o2r.value() == 42.f);
|
|
||||||
|
|
||||||
// lhs is empty, rhs returns empty
|
|
||||||
tl::optional<int> o3;
|
|
||||||
auto o3r = o3.and_then([](int i) { return tl::optional<float>{}; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<float>>::value));
|
|
||||||
REQUIRE(!o3r);
|
|
||||||
|
|
||||||
// rhs returns empty
|
|
||||||
tl::optional<int> o4 = 12;
|
|
||||||
auto o4r = o4.and_then([](int i) { return tl::optional<float>{}; });
|
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<float>>::value));
|
|
||||||
REQUIRE(!o4r);
|
|
||||||
|
|
||||||
struct rval_call_and_then {
|
|
||||||
tl::optional<double> operator()(int) && {
|
|
||||||
return tl::optional<double>(42.0);
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
// ensure that function object is forwarded
|
// ensure that function object is forwarded
|
||||||
tl::optional<int> o5 = 42;
|
tl::optional<int> o3 = 42;
|
||||||
auto o5r = o5.and_then(rval_call_and_then{});
|
auto o3r = o3.map(rval_call_map{});
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<double>>::value));
|
STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<double>>::value));
|
||||||
REQUIRE(o5r.value() == 42);
|
REQUIRE(o3r.value() == 42);
|
||||||
|
|
||||||
// ensure that lhs is forwarded
|
// ensure that lhs is forwarded
|
||||||
tl::optional<int> o6 = 42;
|
tl::optional<int> o4 = 40;
|
||||||
auto o6r =
|
auto o4r = std::move(o4).map([](int &&i) { return i + 2; });
|
||||||
std::move(o6).and_then([](int &&i) { return tl::optional<double>(i); });
|
STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<int>>::value));
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o6r), tl::optional<double>>::value));
|
REQUIRE(o4r.value() == 42);
|
||||||
REQUIRE(o6r.value() == 42);
|
|
||||||
|
|
||||||
// ensure that function object is const-propagated
|
// ensure that lhs is const-propagated
|
||||||
const tl::optional<int> o7 = 42;
|
const tl::optional<int> o5 = 40;
|
||||||
auto o7r = o7.and_then([](const int &i) { return tl::optional<double>(i); });
|
auto o5r = o5.map([](const int &i) { return i + 2; });
|
||||||
STATIC_REQUIRE((std::is_same<decltype(o7r), tl::optional<double>>::value));
|
STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<int>>::value));
|
||||||
REQUIRE(o7r.value() == 42);
|
REQUIRE(o5r.value() == 42);
|
||||||
|
|
||||||
// test each overload in turn
|
// test void return
|
||||||
tl::optional<int> o8 = 42;
|
tl::optional<int> o7 = 40;
|
||||||
auto o8r = o8.and_then([](int i) { return tl::make_optional(42); });
|
auto f7 = [](const int &i) { return; };
|
||||||
REQUIRE(*o8r == 42);
|
auto o7r = o7.map(f7);
|
||||||
|
STATIC_REQUIRE(
|
||||||
|
(std::is_same<decltype(o7r), tl::optional<tl::monostate>>::value));
|
||||||
|
REQUIRE(o7r.has_value());
|
||||||
|
|
||||||
tl::optional<int> o9 = 42;
|
// test each overload in turn
|
||||||
auto o9r =
|
tl::optional<int> o8 = 42;
|
||||||
std::move(o9).and_then([](int i) { return tl::make_optional(42); });
|
auto o8r = o8.map([](int) { return 42; });
|
||||||
REQUIRE(*o9r == 42);
|
REQUIRE(*o8r == 42);
|
||||||
|
|
||||||
const tl::optional<int> o10 = 42;
|
tl::optional<int> o9 = 42;
|
||||||
auto o10r = o10.and_then([](int i) { return tl::make_optional(42); });
|
auto o9r = o9.map([](int) { return; });
|
||||||
REQUIRE(*o10r == 42);
|
REQUIRE(o9r);
|
||||||
|
|
||||||
const tl::optional<int> o11 = 42;
|
tl::optional<int> o12 = 42;
|
||||||
auto o11r =
|
auto o12r = std::move(o12).map([](int) { return 42; });
|
||||||
std::move(o11).and_then([](int i) { return tl::make_optional(42); });
|
REQUIRE(*o12r == 42);
|
||||||
REQUIRE(*o11r == 42);
|
|
||||||
|
|
||||||
tl::optional<int> o16 = tl::nullopt;
|
tl::optional<int> o13 = 42;
|
||||||
auto o16r = o16.and_then([](int i) { return tl::make_optional(42); });
|
auto o13r = std::move(o13).map([](int) { return; });
|
||||||
REQUIRE(!o16r);
|
REQUIRE(o13r);
|
||||||
|
|
||||||
tl::optional<int> o17 = tl::nullopt;
|
const tl::optional<int> o16 = 42;
|
||||||
auto o17r =
|
auto o16r = o16.map([](int) { return 42; });
|
||||||
std::move(o17).and_then([](int i) { return tl::make_optional(42); });
|
REQUIRE(*o16r == 42);
|
||||||
REQUIRE(!o17r);
|
|
||||||
|
|
||||||
const tl::optional<int> o18 = tl::nullopt;
|
const tl::optional<int> o17 = 42;
|
||||||
auto o18r = o18.and_then([](int i) { return tl::make_optional(42); });
|
auto o17r = o17.map([](int) { return; });
|
||||||
REQUIRE(!o18r);
|
REQUIRE(o17r);
|
||||||
|
|
||||||
const tl::optional<int> o19 = tl::nullopt;
|
const tl::optional<int> o20 = 42;
|
||||||
auto o19r =
|
auto o20r = std::move(o20).map([](int) { return 42; });
|
||||||
std::move(o19).and_then([](int i) { return tl::make_optional(42); });
|
REQUIRE(*o20r == 42);
|
||||||
REQUIRE(!o19r);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("constexpr and_then") {
|
const tl::optional<int> o21 = 42;
|
||||||
|
auto o21r = std::move(o21).map([](int) { return; });
|
||||||
|
REQUIRE(o21r);
|
||||||
|
|
||||||
|
tl::optional<int> o24 = tl::nullopt;
|
||||||
|
auto o24r = o24.map([](int) { return 42; });
|
||||||
|
REQUIRE(!o24r);
|
||||||
|
|
||||||
|
tl::optional<int> o25 = tl::nullopt;
|
||||||
|
auto o25r = o25.map([](int) { return; });
|
||||||
|
REQUIRE(!o25r);
|
||||||
|
|
||||||
|
tl::optional<int> o28 = tl::nullopt;
|
||||||
|
auto o28r = std::move(o28).map([](int) { return 42; });
|
||||||
|
REQUIRE(!o28r);
|
||||||
|
|
||||||
|
tl::optional<int> o29 = tl::nullopt;
|
||||||
|
auto o29r = std::move(o29).map([](int) { return; });
|
||||||
|
REQUIRE(!o29r);
|
||||||
|
|
||||||
|
const tl::optional<int> o32 = tl::nullopt;
|
||||||
|
auto o32r = o32.map([](int) { return 42; });
|
||||||
|
REQUIRE(!o32r);
|
||||||
|
|
||||||
|
const tl::optional<int> o33 = tl::nullopt;
|
||||||
|
auto o33r = o33.map([](int) { return; });
|
||||||
|
REQUIRE(!o33r);
|
||||||
|
|
||||||
|
const tl::optional<int> o36 = tl::nullopt;
|
||||||
|
auto o36r = std::move(o36).map([](int) { return 42; });
|
||||||
|
REQUIRE(!o36r);
|
||||||
|
|
||||||
|
const tl::optional<int> o37 = tl::nullopt;
|
||||||
|
auto o37r = std::move(o37).map([](int) { return; });
|
||||||
|
REQUIRE(!o37r);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("map constexpr") {
|
||||||
#if !defined(_MSC_VER) && !defined(TL_OPTIONAL_GCC49)
|
#if !defined(_MSC_VER) && !defined(TL_OPTIONAL_GCC49)
|
||||||
constexpr tl::optional<int> o10 = 42;
|
// test each overload in turn
|
||||||
constexpr auto o10r = o10.and_then(get_opt_int);
|
constexpr tl::optional<int> o16 = 42;
|
||||||
REQUIRE(*o10r == 42);
|
constexpr auto o16r = o16.map(get_int);
|
||||||
|
STATIC_REQUIRE(*o16r == 42);
|
||||||
|
|
||||||
constexpr tl::optional<int> o11 = 42;
|
constexpr tl::optional<int> o18 = 42;
|
||||||
constexpr auto o11r = std::move(o11).and_then(get_opt_int);
|
constexpr auto opt_int = tl::make_optional(get_int);
|
||||||
REQUIRE(*o11r == 42);
|
constexpr auto o18r = o18.map(opt_int);
|
||||||
|
STATIC_REQUIRE(*o18r == 42);
|
||||||
|
|
||||||
constexpr tl::optional<int> o18 = tl::nullopt;
|
constexpr tl::optional<int> o20 = 42;
|
||||||
constexpr auto o18r = o18.and_then(get_opt_int);
|
constexpr auto o20r = std::move(o20).map(get_int);
|
||||||
REQUIRE(!o18r);
|
STATIC_REQUIRE(*o20r == 42);
|
||||||
|
|
||||||
constexpr tl::optional<int> o19 = tl::nullopt;
|
constexpr tl::optional<int> o22 = 42;
|
||||||
constexpr auto o19r = std::move(o19).and_then(get_opt_int);
|
constexpr auto o22r = std::move(o22).map(opt_int);
|
||||||
REQUIRE(!o19r);
|
STATIC_REQUIRE(*o22r == 42);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o32 = tl::nullopt;
|
||||||
|
constexpr auto o32r = o32.map(get_int);
|
||||||
|
STATIC_REQUIRE(!o32r);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o34 = tl::nullopt;
|
||||||
|
constexpr auto o34r = o34.map(opt_int);
|
||||||
|
STATIC_REQUIRE(!o34r);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o36 = tl::nullopt;
|
||||||
|
constexpr auto o36r = std::move(o36).map(get_int);
|
||||||
|
STATIC_REQUIRE(!o36r);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o38 = tl::nullopt;
|
||||||
|
constexpr auto o38r = std::move(o38).map(opt_int);
|
||||||
|
STATIC_REQUIRE(!o38r);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("or else") {
|
SECTION("and_then") {
|
||||||
|
|
||||||
|
// lhs is empty
|
||||||
|
tl::optional<int> o1;
|
||||||
|
auto o1r = o1.and_then([](int i) { return tl::optional<float>{42}; });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o1r), tl::optional<float>>::value));
|
||||||
|
REQUIRE(!o1r);
|
||||||
|
|
||||||
|
// lhs has value
|
||||||
|
tl::optional<int> o2 = 12;
|
||||||
|
auto o2r = o2.and_then([](int i) { return tl::optional<float>{42}; });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<float>>::value));
|
||||||
|
REQUIRE(o2r.value() == 42.f);
|
||||||
|
|
||||||
|
// lhs is empty, rhs returns empty
|
||||||
|
tl::optional<int> o3;
|
||||||
|
auto o3r = o3.and_then([](int i) { return tl::optional<float>{}; });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o3r), tl::optional<float>>::value));
|
||||||
|
REQUIRE(!o3r);
|
||||||
|
|
||||||
|
// rhs returns empty
|
||||||
|
tl::optional<int> o4 = 12;
|
||||||
|
auto o4r = o4.and_then([](int i) { return tl::optional<float>{}; });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o4r), tl::optional<float>>::value));
|
||||||
|
REQUIRE(!o4r);
|
||||||
|
|
||||||
|
struct rval_call_and_then {
|
||||||
|
tl::optional<double> operator()(int) && {
|
||||||
|
return tl::optional<double>(42.0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// ensure that function object is forwarded
|
||||||
|
tl::optional<int> o5 = 42;
|
||||||
|
auto o5r = o5.and_then(rval_call_and_then{});
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o5r), tl::optional<double>>::value));
|
||||||
|
REQUIRE(o5r.value() == 42);
|
||||||
|
|
||||||
|
// ensure that lhs is forwarded
|
||||||
|
tl::optional<int> o6 = 42;
|
||||||
|
auto o6r =
|
||||||
|
std::move(o6).and_then([](int &&i) { return tl::optional<double>(i); });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o6r), tl::optional<double>>::value));
|
||||||
|
REQUIRE(o6r.value() == 42);
|
||||||
|
|
||||||
|
// ensure that function object is const-propagated
|
||||||
|
const tl::optional<int> o7 = 42;
|
||||||
|
auto o7r =
|
||||||
|
o7.and_then([](const int &i) { return tl::optional<double>(i); });
|
||||||
|
STATIC_REQUIRE((std::is_same<decltype(o7r), tl::optional<double>>::value));
|
||||||
|
REQUIRE(o7r.value() == 42);
|
||||||
|
|
||||||
|
// test each overload in turn
|
||||||
|
tl::optional<int> o8 = 42;
|
||||||
|
auto o8r = o8.and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(*o8r == 42);
|
||||||
|
|
||||||
|
tl::optional<int> o9 = 42;
|
||||||
|
auto o9r =
|
||||||
|
std::move(o9).and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(*o9r == 42);
|
||||||
|
|
||||||
|
const tl::optional<int> o10 = 42;
|
||||||
|
auto o10r = o10.and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(*o10r == 42);
|
||||||
|
|
||||||
|
const tl::optional<int> o11 = 42;
|
||||||
|
auto o11r =
|
||||||
|
std::move(o11).and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(*o11r == 42);
|
||||||
|
|
||||||
|
tl::optional<int> o16 = tl::nullopt;
|
||||||
|
auto o16r = o16.and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(!o16r);
|
||||||
|
|
||||||
|
tl::optional<int> o17 = tl::nullopt;
|
||||||
|
auto o17r =
|
||||||
|
std::move(o17).and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(!o17r);
|
||||||
|
|
||||||
|
const tl::optional<int> o18 = tl::nullopt;
|
||||||
|
auto o18r = o18.and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(!o18r);
|
||||||
|
|
||||||
|
const tl::optional<int> o19 = tl::nullopt;
|
||||||
|
auto o19r =
|
||||||
|
std::move(o19).and_then([](int i) { return tl::make_optional(42); });
|
||||||
|
REQUIRE(!o19r);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("constexpr and_then") {
|
||||||
|
#if !defined(_MSC_VER) && !defined(TL_OPTIONAL_GCC49)
|
||||||
|
constexpr tl::optional<int> o10 = 42;
|
||||||
|
constexpr auto o10r = o10.and_then(get_opt_int);
|
||||||
|
REQUIRE(*o10r == 42);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o11 = 42;
|
||||||
|
constexpr auto o11r = std::move(o11).and_then(get_opt_int);
|
||||||
|
REQUIRE(*o11r == 42);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o18 = tl::nullopt;
|
||||||
|
constexpr auto o18r = o18.and_then(get_opt_int);
|
||||||
|
REQUIRE(!o18r);
|
||||||
|
|
||||||
|
constexpr tl::optional<int> o19 = tl::nullopt;
|
||||||
|
constexpr auto o19r = std::move(o19).and_then(get_opt_int);
|
||||||
|
REQUIRE(!o19r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("or else") {
|
||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
REQUIRE(*(o1.or_else([] { return tl::make_optional(13); })) == 42);
|
REQUIRE(*(o1.or_else([] { return tl::make_optional(13); })) == 42);
|
||||||
|
|
||||||
tl::optional<int> o2;
|
tl::optional<int> o2;
|
||||||
REQUIRE(*(o2.or_else([] { return tl::make_optional(13); })) == 13);
|
REQUIRE(*(o2.or_else([] { return tl::make_optional(13); })) == 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("disjunction") {
|
SECTION("disjunction") {
|
||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
tl::optional<int> o2 = 12;
|
tl::optional<int> o2 = 12;
|
||||||
tl::optional<int> o3;
|
tl::optional<int> o3;
|
||||||
@ -358,9 +288,9 @@ SECTION("disjunction") {
|
|||||||
REQUIRE(*o2.disjunction(o3) == 12);
|
REQUIRE(*o2.disjunction(o3) == 12);
|
||||||
REQUIRE(*o3.disjunction(o1) == 42);
|
REQUIRE(*o3.disjunction(o1) == 42);
|
||||||
REQUIRE(*o3.disjunction(o2) == 12);
|
REQUIRE(*o3.disjunction(o2) == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("conjunction") {
|
SECTION("conjunction") {
|
||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
REQUIRE(*o1.conjunction(42.0) == 42.0);
|
REQUIRE(*o1.conjunction(42.0) == 42.0);
|
||||||
REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
|
REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
|
||||||
@ -370,25 +300,27 @@ SECTION("conjunction") {
|
|||||||
REQUIRE(!o2.conjunction(42.0));
|
REQUIRE(!o2.conjunction(42.0));
|
||||||
REQUIRE(!o2.conjunction(std::string{"hello"}));
|
REQUIRE(!o2.conjunction(std::string{"hello"}));
|
||||||
REQUIRE(!o2.conjunction(tl::nullopt));
|
REQUIRE(!o2.conjunction(tl::nullopt));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("map_or") {
|
SECTION("map_or") {
|
||||||
tl::optional<int> o1 = 21;
|
tl::optional<int> o1 = 21;
|
||||||
REQUIRE((o1.map_or([](int x) { return x * 2; }, 13)) == 42);
|
REQUIRE((o1.map_or([](int x) { return x * 2; }, 13)) == 42);
|
||||||
|
|
||||||
tl::optional<int> o2;
|
tl::optional<int> o2;
|
||||||
REQUIRE((o2.map_or([](int x) { return x * 2; }, 13)) == 13);
|
REQUIRE((o2.map_or([](int x) { return x * 2; }, 13)) == 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("map_or_else") {
|
SECTION("map_or_else") {
|
||||||
tl::optional<int> o1 = 21;
|
tl::optional<int> o1 = 21;
|
||||||
REQUIRE((o1.map_or_else([](int x) { return x * 2; }, []{return 13;})) == 42);
|
REQUIRE((o1.map_or_else([](int x) { return x * 2; }, [] { return 13; })) ==
|
||||||
|
42);
|
||||||
|
|
||||||
tl::optional<int> o2;
|
tl::optional<int> o2;
|
||||||
REQUIRE((o2.map_or_else([](int x) { return x * 2; }, []{return 13;})) == 13);
|
REQUIRE((o2.map_or_else([](int x) { return x * 2; }, [] { return 13; })) ==
|
||||||
}
|
13);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("take") {
|
SECTION("take") {
|
||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
REQUIRE(*o1.take() == 42);
|
REQUIRE(*o1.take() == 42);
|
||||||
REQUIRE(!o1);
|
REQUIRE(!o1);
|
||||||
@ -396,6 +328,18 @@ SECTION("take") {
|
|||||||
tl::optional<int> o2;
|
tl::optional<int> o2;
|
||||||
REQUIRE(!o2.take());
|
REQUIRE(!o2.take());
|
||||||
REQUIRE(!o2);
|
REQUIRE(!o2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
;
|
struct foo {
|
||||||
|
void non_const() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef TL_OPTIONAL_CXX14
|
||||||
|
// Reported by Mark Papadakis
|
||||||
|
SECTION("map const correctness") {
|
||||||
|
tl::optional<foo> f = foo{};
|
||||||
|
auto l = [](auto &&x) { x.non_const(); };
|
||||||
|
f.map(l);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user