2017-09-29 19:45:17 +01:00
|
|
|
///
|
|
|
|
|
// optional - An implementation of std::optional with extensions
|
|
|
|
|
// Written in 2017 by Simon Brand (@TartanLlama)
|
|
|
|
|
//
|
|
|
|
|
// To the extent possible under law, the author(s) have dedicated all
|
|
|
|
|
// copyright and related and neighboring rights to this software to the
|
|
|
|
|
// public domain worldwide. This software is distributed without any warranty.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the CC0 Public Domain Dedication
|
2017-10-02 08:58:09 +01:00
|
|
|
// along with this software. If not, see
|
|
|
|
|
// <http://creativecommons.org/publicdomain/zero/1.0/>.
|
2017-09-29 19:45:17 +01:00
|
|
|
///
|
|
|
|
|
|
2017-10-24 09:01:24 +01:00
|
|
|
#ifndef TL_OPTIONAL_HPP
|
|
|
|
|
#define TL_OPTIONAL_HPP
|
|
|
|
|
|
2017-10-01 14:54:19 +01:00
|
|
|
#include <exception>
|
2017-10-01 15:27:57 +01:00
|
|
|
#include <functional>
|
2017-10-02 08:58:09 +01:00
|
|
|
#include <new>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include <utility>
|
2017-09-29 19:45:17 +01:00
|
|
|
|
2017-10-21 22:21:49 +01:00
|
|
|
#if (defined(_MSC_VER) && _MSC_VER == 1900)
|
|
|
|
|
#define TL_OPTIONAL_MSVC2015
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9)
|
|
|
|
|
#define TL_OPTIONAL_GCC49
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-25 09:17:45 +01:00
|
|
|
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4)
|
2017-10-25 09:27:10 +01:00
|
|
|
#define TL_OPTIONAL_GCC54
|
2017-10-25 09:17:45 +01:00
|
|
|
#endif
|
|
|
|
|
|
2017-10-21 22:31:42 +01:00
|
|
|
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9)
|
|
|
|
|
#define TL_OPTIONAL_NO_CONSTRR
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#if __cplusplus > 201103L
|
|
|
|
|
#define TL_OPTIONAL_CXX14
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-24 15:59:38 +01:00
|
|
|
#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \
|
|
|
|
|
defined(TL_OPTIONAL_GCC49)) && \
|
|
|
|
|
!defined(TL_OPTIONAL_GCC50)
|
2017-10-21 09:33:16 +01:00
|
|
|
/// \exclude
|
2017-10-02 20:18:40 +01:00
|
|
|
#define TL_OPTIONAL_11_CONSTEXPR
|
|
|
|
|
#else
|
2017-10-21 09:33:16 +01:00
|
|
|
/// \exclude
|
2017-10-02 20:18:40 +01:00
|
|
|
#define TL_OPTIONAL_11_CONSTEXPR constexpr
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-09-29 19:45:17 +01:00
|
|
|
namespace tl {
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \brief Used to represent an optional with no data; essentially a bool
|
2017-10-02 12:03:52 +01:00
|
|
|
class monostate {};
|
2017-10-21 09:33:16 +01:00
|
|
|
|
|
|
|
|
/// \brief A tag type to tell optional to construct its value in-place
|
|
|
|
|
struct in_place_t {
|
|
|
|
|
explicit in_place_t() = default;
|
|
|
|
|
};
|
|
|
|
|
/// \brief A tag to tell optional to construct its value in-place
|
|
|
|
|
static constexpr in_place_t in_place{};
|
|
|
|
|
|
|
|
|
|
template <class T> class optional;
|
|
|
|
|
|
|
|
|
|
/// \exclude
|
2017-10-02 08:58:09 +01:00
|
|
|
namespace detail {
|
2017-10-21 22:55:58 +01:00
|
|
|
|
|
|
|
|
// C++14-style aliases for brevity
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class T> using remove_const_t = typename std::remove_const<T>::type;
|
|
|
|
|
template <class T>
|
|
|
|
|
using remove_reference_t = typename std::remove_reference<T>::type;
|
|
|
|
|
template <class T> using decay_t = typename std::decay<T>::type;
|
|
|
|
|
template <bool E, class T = void>
|
|
|
|
|
using enable_if_t = typename std::enable_if<E, T>::type;
|
|
|
|
|
template <bool B, class T, class F>
|
|
|
|
|
using conditional_t = typename std::conditional<B, T, F>::type;
|
|
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// std::conjunction from C++17
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class...> struct conjunction : std::true_type {};
|
|
|
|
|
template <class B> struct conjunction<B> : B {};
|
|
|
|
|
template <class B, class... Bs>
|
|
|
|
|
struct conjunction<B, Bs...>
|
|
|
|
|
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
|
|
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// std::void_t from C++17
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class...> struct voider { using type = void; };
|
|
|
|
|
template <class... Ts> using void_t = typename voider<Ts...>::type;
|
2017-10-02 12:03:52 +01:00
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// Trait for checking if a type is a tl::optional
|
2017-10-02 12:03:52 +01:00
|
|
|
template <class T> struct is_optional_impl : std::false_type {};
|
|
|
|
|
template <class T> struct is_optional_impl<optional<T>> : std::true_type {};
|
|
|
|
|
template <class T> using is_optional = is_optional_impl<decay_t<T>>;
|
|
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// std::invoke from C++17
|
2017-10-02 12:03:52 +01:00
|
|
|
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
2017-10-17 13:08:31 +01:00
|
|
|
template <typename Fn, typename... Args,
|
|
|
|
|
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>{}>,
|
|
|
|
|
int = 0>
|
2017-10-02 12:03:52 +01:00
|
|
|
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
|
|
|
|
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
|
|
|
|
|
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
|
|
|
|
|
return std::mem_fn(f)(std::forward<Args>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 13:08:31 +01:00
|
|
|
template <typename Fn, typename... Args,
|
|
|
|
|
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
|
2017-10-02 12:03:52 +01:00
|
|
|
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
|
|
|
|
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
|
|
|
|
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
|
|
|
|
return std::forward<Fn>(f)(std::forward<Args>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// std::invoke_result from C++17
|
2017-10-02 12:03:52 +01:00
|
|
|
template <class F, class, class... Us> struct invoke_result_impl;
|
|
|
|
|
|
|
|
|
|
template <class F, class... Us>
|
|
|
|
|
struct invoke_result_impl<
|
|
|
|
|
F, decltype(invoke(std::declval<F>(), std::declval<Us>()...), void()),
|
|
|
|
|
Us...> {
|
|
|
|
|
using type = decltype(invoke(std::declval<F>(), std::declval<Us>()...));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <class F, class... Us>
|
|
|
|
|
using invoke_result = invoke_result_impl<F, void, Us...>;
|
|
|
|
|
|
|
|
|
|
template <class F, class... Us>
|
|
|
|
|
using invoke_result_t = typename invoke_result<F, Us...>::type;
|
|
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// Change void to tl::monostate
|
2017-10-02 12:03:52 +01:00
|
|
|
template <class U>
|
2017-10-02 14:00:56 +01:00
|
|
|
using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;
|
2017-10-02 12:03:52 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
template <class F, class U, class = invoke_result_t<F, U>>
|
|
|
|
|
using get_map_return = optional<fixup_void<invoke_result_t<F, U>>>;
|
2017-10-02 12:03:52 +01:00
|
|
|
|
2017-10-21 22:55:58 +01:00
|
|
|
// Check if invoking F for some Us returns void
|
2017-10-24 15:07:29 +01:00
|
|
|
template <class F, class = void, class... U> struct returns_void_impl;
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class F, class... U>
|
2017-10-24 15:07:29 +01:00
|
|
|
struct returns_void_impl<F, void_t<invoke_result_t<F, U...>>, U...>
|
|
|
|
|
: std::is_void<invoke_result_t<F, U...>> {};
|
|
|
|
|
template <class F, class... U>
|
|
|
|
|
using returns_void = returns_void_impl<F, void, U...>;
|
2017-10-02 14:00:56 +01:00
|
|
|
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class T, class... U>
|
|
|
|
|
using enable_if_ret_void = enable_if_t<returns_void<T &&, U...>::value>;
|
2017-10-02 14:00:56 +01:00
|
|
|
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class T, class... U>
|
|
|
|
|
using disable_if_ret_void = enable_if_t<!returns_void<T &&, U...>::value>;
|
2017-10-02 08:58:09 +01:00
|
|
|
|
|
|
|
|
template <class T, class U>
|
|
|
|
|
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>;
|
|
|
|
|
|
|
|
|
|
template <class T, class U, class Other>
|
|
|
|
|
using enable_from_other = detail::enable_if_t<
|
|
|
|
|
std::is_constructible<T, Other>::value &&
|
|
|
|
|
!std::is_constructible<T, optional<U> &>::value &&
|
|
|
|
|
!std::is_constructible<T, optional<U> &&>::value &&
|
|
|
|
|
!std::is_constructible<T, const optional<U> &>::value &&
|
|
|
|
|
!std::is_constructible<T, const optional<U> &&>::value &&
|
|
|
|
|
!std::is_convertible<optional<U> &, T>::value &&
|
|
|
|
|
!std::is_convertible<optional<U> &&, T>::value &&
|
|
|
|
|
!std::is_convertible<const optional<U> &, T>::value &&
|
|
|
|
|
!std::is_convertible<const optional<U> &&, T>::value>;
|
|
|
|
|
|
|
|
|
|
template <class T, class U>
|
|
|
|
|
using enable_assign_forward = detail::enable_if_t<
|
|
|
|
|
!std::is_same<optional<T>, detail::decay_t<U>>::value &&
|
|
|
|
|
!detail::conjunction<std::is_scalar<T>,
|
|
|
|
|
std::is_same<T, detail::decay_t<U>>>::value &&
|
|
|
|
|
std::is_constructible<T, U>::value && std::is_assignable<T &, U>::value>;
|
|
|
|
|
|
|
|
|
|
template <class T, class U, class Other>
|
|
|
|
|
using enable_assign_from_other = detail::enable_if_t<
|
|
|
|
|
std::is_constructible<T, Other>::value &&
|
|
|
|
|
std::is_assignable<T &, Other>::value &&
|
|
|
|
|
!std::is_constructible<T, optional<U> &>::value &&
|
|
|
|
|
!std::is_constructible<T, optional<U> &&>::value &&
|
|
|
|
|
!std::is_constructible<T, const optional<U> &>::value &&
|
|
|
|
|
!std::is_constructible<T, const optional<U> &&>::value &&
|
|
|
|
|
!std::is_convertible<optional<U> &, T>::value &&
|
|
|
|
|
!std::is_convertible<optional<U> &&, T>::value &&
|
|
|
|
|
!std::is_convertible<const optional<U> &, T>::value &&
|
|
|
|
|
!std::is_convertible<const optional<U> &&, T>::value &&
|
|
|
|
|
!std::is_assignable<T &, optional<U> &>::value &&
|
|
|
|
|
!std::is_assignable<T &, optional<U> &&>::value &&
|
|
|
|
|
!std::is_assignable<T &, const optional<U> &>::value &&
|
|
|
|
|
!std::is_assignable<T &, const optional<U> &&>::value>;
|
|
|
|
|
|
2017-10-17 11:54:57 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
// 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 {};
|
|
|
|
|
#else
|
2017-10-02 08:58:09 +01:00
|
|
|
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
|
|
|
|
namespace swap_adl_tests {
|
|
|
|
|
// if swap ADL finds this then it would call std::swap otherwise (same
|
|
|
|
|
// signature)
|
|
|
|
|
struct tag {};
|
|
|
|
|
|
|
|
|
|
template <class T> tag swap(T &, T &);
|
|
|
|
|
template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
|
|
|
|
|
|
|
|
|
|
// helper functions to test if an unqualified swap is possible, and if it
|
|
|
|
|
// becomes std::swap
|
|
|
|
|
template <class, class> std::false_type can_swap(...) noexcept(false);
|
|
|
|
|
template <class T, class U,
|
|
|
|
|
class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
|
|
|
|
|
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
|
|
|
|
|
std::declval<U &>())));
|
|
|
|
|
|
|
|
|
|
template <class, class> std::false_type uses_std(...);
|
|
|
|
|
template <class T, class U>
|
|
|
|
|
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
|
|
|
|
|
uses_std(int);
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
|
struct is_std_swap_noexcept
|
|
|
|
|
: std::integral_constant<bool,
|
|
|
|
|
std::is_nothrow_move_constructible<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> {};
|
|
|
|
|
|
|
|
|
|
template <class T, class U>
|
|
|
|
|
struct is_adl_swap_noexcept
|
|
|
|
|
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
|
2017-10-17 11:54:57 +01:00
|
|
|
} // namespace swap_adl_tests
|
2017-10-01 21:19:46 +01:00
|
|
|
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class T, class U = T>
|
|
|
|
|
struct is_swappable
|
|
|
|
|
: std::integral_constant<
|
|
|
|
|
bool,
|
|
|
|
|
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
|
|
|
|
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
|
|
|
|
|
(std::is_move_assignable<T>::value &&
|
|
|
|
|
std::is_move_constructible<T>::value))> {};
|
|
|
|
|
|
|
|
|
|
template <class T, std::size_t N>
|
|
|
|
|
struct is_swappable<T[N], T[N]>
|
|
|
|
|
: std::integral_constant<
|
|
|
|
|
bool,
|
|
|
|
|
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
|
|
|
|
|
(!decltype(
|
|
|
|
|
detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
|
|
|
|
|
is_swappable<T, T>::value)> {};
|
|
|
|
|
|
|
|
|
|
template <class T, class U = T>
|
|
|
|
|
struct is_nothrow_swappable
|
|
|
|
|
: 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))> {
|
|
|
|
|
};
|
2017-10-11 19:18:08 +01:00
|
|
|
#endif
|
|
|
|
|
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class T, bool = ::std::is_trivially_destructible<T>::value>
|
|
|
|
|
struct optional_storage_base {
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
|
|
|
|
|
: m_dummy(), m_has_value(false) {}
|
2017-10-02 08:58:09 +01:00
|
|
|
|
|
|
|
|
template <class... U>
|
2017-10-21 22:21:49 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) noexcept
|
2017-10-02 08:58:09 +01:00
|
|
|
: m_value(std::forward<U>(u)...), m_has_value(true) {}
|
|
|
|
|
|
|
|
|
|
~optional_storage_base() {
|
|
|
|
|
if (m_has_value) {
|
|
|
|
|
m_value.~T();
|
|
|
|
|
m_has_value = false;
|
2017-09-29 20:14:29 +01:00
|
|
|
}
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct dummy {};
|
|
|
|
|
union {
|
|
|
|
|
dummy m_dummy;
|
|
|
|
|
T m_value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool m_has_value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <class T> struct optional_storage_base<T, true> {
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
|
2017-10-17 13:13:15 +01:00
|
|
|
: m_dummy(), m_has_value(false) {}
|
2017-10-02 08:58:09 +01:00
|
|
|
|
|
|
|
|
template <class... U>
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) noexcept
|
2017-10-02 08:58:09 +01:00
|
|
|
: m_value(std::forward<U>(u)...), m_has_value(true) {}
|
|
|
|
|
|
|
|
|
|
~optional_storage_base() = default;
|
|
|
|
|
|
|
|
|
|
struct dummy {};
|
|
|
|
|
union {
|
|
|
|
|
dummy m_dummy;
|
|
|
|
|
T m_value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool m_has_value = false;
|
|
|
|
|
};
|
2017-10-24 15:07:29 +01:00
|
|
|
|
2017-10-17 11:54:57 +01:00
|
|
|
} // namespace detail
|
2017-09-29 20:14:29 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \brief A tag type to represent an empty optional
|
|
|
|
|
struct nullopt_t {
|
|
|
|
|
struct do_not_use {};
|
|
|
|
|
constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
|
|
|
|
|
};
|
|
|
|
|
/// \brief Represents an empty optional
|
|
|
|
|
/// \synopsis static constexpr nullopt_t nullopt;
|
|
|
|
|
///
|
|
|
|
|
/// *Examples*:
|
|
|
|
|
/// ```
|
|
|
|
|
/// tl::optional<int> a = tl::nullopt;
|
|
|
|
|
/// void foo (tl::optional<int>);
|
|
|
|
|
/// foo(tl::nullopt); //pass an empty optional
|
|
|
|
|
/// ```
|
|
|
|
|
static constexpr nullopt_t nullopt{nullopt_t::do_not_use{},
|
|
|
|
|
nullopt_t::do_not_use{}};
|
|
|
|
|
|
|
|
|
|
class bad_optional_access : public std::exception {
|
|
|
|
|
public:
|
|
|
|
|
bad_optional_access() = default;
|
|
|
|
|
const char *what() const noexcept { return "Optional has no value"; }
|
|
|
|
|
};
|
2017-10-21 09:33:16 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
/// 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.
|
2017-10-02 08:58:09 +01:00
|
|
|
template <class T> class optional : private detail::optional_storage_base<T> {
|
|
|
|
|
using base = detail::optional_storage_base<T>;
|
|
|
|
|
|
|
|
|
|
public:
|
2017-10-24 15:46:07 +01:00
|
|
|
// The different versions for C++14 and 11 are needed because deduced return
|
|
|
|
|
// types are not SFINAE-safe. C.f.
|
|
|
|
|
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
|
2017-10-24 15:32:22 +01:00
|
|
|
#ifdef TL_OPTIONAL_CXX14
|
|
|
|
|
/// \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
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \group and_then
|
2017-10-24 15:07:29 +01:00
|
|
|
/// 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) &;
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class F>
|
2017-10-24 15:32:22 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &> and_then(F &&f) & {
|
|
|
|
|
using result = detail::invoke_result_t<F, T &>;
|
2017-10-21 19:04:41 +01:00
|
|
|
static_assert(detail::is_optional<result>::value,
|
|
|
|
|
"F must return an optional");
|
2017-10-21 09:33:16 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
|
|
|
: result(nullopt);
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group and_then
|
|
|
|
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class F>
|
2017-10-24 15:32:22 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && {
|
|
|
|
|
using result = detail::invoke_result_t<F, T &&>;
|
2017-10-21 19:04:41 +01:00
|
|
|
static_assert(detail::is_optional<result>::value,
|
|
|
|
|
"F must return an optional");
|
2017-10-02 08:58:09 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
|
|
|
: result(nullopt);
|
|
|
|
|
}
|
2017-10-02 08:58:09 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \group and_then
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class F>
|
2017-10-24 15:32:22 +01:00
|
|
|
constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & {
|
|
|
|
|
using result = detail::invoke_result_t<F, const T &>;
|
2017-10-21 19:04:41 +01:00
|
|
|
static_assert(detail::is_optional<result>::value,
|
|
|
|
|
"F must return an optional");
|
2017-10-02 08:58:09 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
|
|
|
: result(nullopt);
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group and_then
|
|
|
|
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class F>
|
2017-10-24 15:32:22 +01:00
|
|
|
constexpr detail::invoke_result_t<F, const T &&> and_then(F &&f) const && {
|
|
|
|
|
using result = detail::invoke_result_t<F, const T &&>;
|
2017-10-21 19:04:41 +01:00
|
|
|
static_assert(detail::is_optional<result>::value,
|
|
|
|
|
"F must return an optional");
|
2017-10-02 08:58:09 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
|
|
|
: result(nullopt);
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-24 15:32:22 +01:00
|
|
|
#endif
|
2017-10-02 08:58:09 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifdef TL_OPTIONAL_CXX14
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \brief Carries out some operation on the stored object if there is one.
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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) &;
|
2017-10-24 15:55:40 +01:00
|
|
|
template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & {
|
2017-10-24 15:07:29 +01:00
|
|
|
return map_impl(*this, std::forward<F>(f));
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:55:40 +01:00
|
|
|
template <class F> TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && {
|
2017-10-24 15:07:29 +01:00
|
|
|
return map_impl(std::move(*this), std::forward<F>(f));
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:46:07 +01:00
|
|
|
template <class F> constexpr auto map(F &&f) const & {
|
2017-10-24 15:07:29 +01:00
|
|
|
return map_impl(*this, std::forward<F>(f));
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:46:07 +01:00
|
|
|
template <class F> constexpr auto map(F &&f) const && {
|
2017-10-24 15:07:29 +01:00
|
|
|
return map_impl(std::move(*this), std::forward<F>(f));
|
2017-10-02 08:58:09 +01:00
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#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>
|
2017-10-24 15:46:07 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval<optional &>(),
|
|
|
|
|
std::declval<F &&>()))
|
2017-10-24 15:07:29 +01:00
|
|
|
map(F &&f) & {
|
|
|
|
|
return map_impl(*this, std::forward<F>(f));
|
2017-10-02 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
template <class F>
|
2017-10-24 15:46:07 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval<optional &&>(),
|
|
|
|
|
std::declval<F &&>()))
|
2017-10-24 15:07:29 +01:00
|
|
|
map(F &&f) && {
|
|
|
|
|
return map_impl(std::move(*this), std::forward<F>(f));
|
2017-10-02 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
template <class F>
|
2017-10-24 15:46:07 +01:00
|
|
|
constexpr decltype(map_impl(std::declval<const optional &>(),
|
|
|
|
|
std::declval<F &&>()))
|
2017-10-24 15:07:29 +01:00
|
|
|
map(F &&f) const & {
|
|
|
|
|
return map_impl(*this, std::forward<F>(f));
|
2017-10-02 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
|
|
|
|
template <class F>
|
2017-10-24 15:46:07 +01:00
|
|
|
constexpr decltype(map_impl(std::declval<const optional &&>(),
|
|
|
|
|
std::declval<F &&>()))
|
2017-10-24 15:07:29 +01:00
|
|
|
map(F &&f) const && {
|
|
|
|
|
return map_impl(std::move(*this), std::forward<F>(f));
|
2017-10-02 12:03:52 +01:00
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
|
|
|
|
#endif
|
2017-10-04 10:45:48 +01:00
|
|
|
|
2017-10-21 09:33:16 +01:00
|
|
|
/// \brief Calls `f` if the optional is empty
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \synopsis template <class F> optional<T> or_else (F &&f) &;
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class F, detail::enable_if_ret_void<F> * = nullptr>
|
2017-10-21 22:21:49 +01:00
|
|
|
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
2017-10-06 10:03:12 +01:00
|
|
|
if (has_value())
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
std::forward<F>(f)();
|
|
|
|
|
return nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
2017-10-21 22:21:49 +01:00
|
|
|
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & {
|
2017-10-06 10:03:12 +01:00
|
|
|
return has_value() ? *this : std::forward<F>(f)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group or_else
|
|
|
|
|
/// \synopsis template <class F> optional<T> or_else (F &&f) &&;
|
2017-10-06 10:03:12 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
2017-10-21 22:21:49 +01:00
|
|
|
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && {
|
2017-10-06 10:03:12 +01:00
|
|
|
return has_value() ? std::move(*this) : std::forward<F>(f)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group or_else
|
|
|
|
|
/// \synopsis template <class F> optional<T> or_else (F &&f) const &;
|
2017-10-06 10:03:12 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \exclude
|
2017-10-06 10:03:12 +01:00
|
|
|
template <class F, detail::disable_if_ret_void<F> * = nullptr>
|
2017-10-21 22:21:49 +01:00
|
|
|
optional<T> TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & {
|
2017-10-06 10:03:12 +01:00
|
|
|
return has_value() ? *this : std::forward<F>(f)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
2017-10-06 10:03:12 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
2017-10-06 10:03:12 +01:00
|
|
|
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)();
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 10:35:06 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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
|
2017-10-04 10:45:48 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group map_or
|
2017-10-04 10:45:48 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 10:35:06 +01:00
|
|
|
/// \group map_or
|
2017-10-04 10:45:48 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group map_or
|
2017-10-04 10:45:48 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-04 10:45:48 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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) &;
|
2017-10-21 20:08:43 +01:00
|
|
|
template <class F, class U>
|
|
|
|
|
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) & {
|
2017-10-04 10:45:48 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
|
|
|
: std::forward<U>(u)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group map_or_else
|
2017-10-21 20:08:43 +01:00
|
|
|
/// \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) && {
|
2017-10-04 10:45:48 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
|
|
|
: std::forward<U>(u)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 10:35:06 +01:00
|
|
|
/// \group map_or_else
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
|
|
|
|
/// const &;
|
2017-10-21 20:08:43 +01:00
|
|
|
template <class F, class U>
|
|
|
|
|
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const & {
|
2017-10-04 10:45:48 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), **this)
|
|
|
|
|
: std::forward<U>(u)();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group map_or_else
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
|
|
|
|
|
/// const &&;
|
2017-10-21 20:08:43 +01:00
|
|
|
template <class F, class U>
|
|
|
|
|
detail::invoke_result_t<U> map_or_else(F &&f, U &&u) const && {
|
2017-10-04 10:45:48 +01:00
|
|
|
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this))
|
|
|
|
|
: std::forward<U>(u)();
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-02 12:03:52 +01:00
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \returns `u` if `*this` has a value, otherwise an empty optional.
|
2017-10-21 20:08:43 +01:00
|
|
|
template <class U>
|
2017-10-24 15:07:29 +01:00
|
|
|
constexpr optional<typename std::decay<U>::type> conjunction(U &&u) const {
|
2017-10-21 20:08:43 +01:00
|
|
|
using result = optional<detail::decay_t<U>>;
|
|
|
|
|
return has_value() ? result{u} : result{nullopt};
|
2017-10-21 19:41:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \returns `rhs` if `*this` is empty, otherwise the current value.
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? *this : rhs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
constexpr optional disjunction(const optional &rhs) const & {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? *this : rhs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? std::move(*this) : rhs;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
constexpr optional disjunction(const optional &rhs) const && {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? std::move(*this) : rhs;
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 19:41:18 +01:00
|
|
|
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? *this : std::move(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
constexpr optional disjunction(optional &&rhs) const & {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? *this : std::move(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? std::move(*this) : std::move(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group disjunction
|
2017-10-24 15:07:29 +01:00
|
|
|
constexpr optional disjunction(optional &&rhs) const && {
|
2017-10-21 19:41:18 +01:00
|
|
|
return has_value() ? std::move(*this) : std::move(rhs);
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 19:41:18 +01:00
|
|
|
|
|
|
|
|
/// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:41:18 +01:00
|
|
|
/// \group take
|
|
|
|
|
optional take() const && {
|
|
|
|
|
optional ret = std::move(*this);
|
|
|
|
|
reset();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 19:41:18 +01:00
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
using value_type = T;
|
|
|
|
|
|
|
|
|
|
/// Constructs an optional that does not contain a value.
|
|
|
|
|
/// \group ctor_empty
|
|
|
|
|
constexpr optional() noexcept = default;
|
|
|
|
|
|
|
|
|
|
/// \group ctor_empty
|
2017-10-21 21:01:45 +01:00
|
|
|
constexpr optional(nullopt_t) noexcept {}
|
2017-10-21 19:04:41 +01:00
|
|
|
|
|
|
|
|
/// 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) {
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(*rhs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO conditionally disable
|
|
|
|
|
/// 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) noexcept(
|
|
|
|
|
std::is_nothrow_move_constructible<T>::value) {
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::move(*rhs));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Constructs the stored value in-place using the given arguments.
|
|
|
|
|
/// \group in_place
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \synopsis template <class... Args> constexpr explicit optional(in_place_t,
|
|
|
|
|
/// Args&&... args);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class... Args>
|
|
|
|
|
constexpr explicit optional(
|
|
|
|
|
detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
|
|
|
|
|
Args &&... args)
|
|
|
|
|
: base(in_place, std::forward<Args>(args)...) {}
|
|
|
|
|
|
|
|
|
|
/// \group in_place
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \synopsis template <class U, class... Args>\nconstexpr explicit
|
|
|
|
|
/// optional(in_place_t, std::initializer_list<U>&, Args&&... args);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class U, class... Args>
|
|
|
|
|
TL_OPTIONAL_11_CONSTEXPR explicit optional(
|
|
|
|
|
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &,
|
|
|
|
|
Args &&...>::value,
|
|
|
|
|
in_place_t>,
|
|
|
|
|
std::initializer_list<U> il, Args &&... args) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(il, std::forward<Args>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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_forward_value<T, U> * = nullptr>
|
|
|
|
|
constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {}
|
|
|
|
|
|
|
|
|
|
/// \exclude
|
|
|
|
|
template <
|
|
|
|
|
class U = T,
|
|
|
|
|
detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr,
|
|
|
|
|
detail::enable_forward_value<T, U> * = nullptr>
|
|
|
|
|
constexpr explicit optional(U &&u) : base(in_place, std::forward<U>(u)) {}
|
|
|
|
|
|
|
|
|
|
/// 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>
|
|
|
|
|
optional(const optional<U> &rhs) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(*rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \exclude
|
|
|
|
|
template <class U, detail::enable_from_other<T, U, const U &> * = nullptr,
|
|
|
|
|
detail::enable_if_t<!std::is_convertible<const U &, T>::value> * =
|
|
|
|
|
nullptr>
|
|
|
|
|
explicit optional(const optional<U> &rhs) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(*rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Converting move constructor.
|
|
|
|
|
/// \synopsis template <class U> optional(optional<U> &&rhs);
|
|
|
|
|
template <
|
|
|
|
|
class U, detail::enable_from_other<T, U, U &&> * = nullptr,
|
|
|
|
|
detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr>
|
|
|
|
|
optional(optional<U> &&rhs) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::move(*rhs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \exclude
|
|
|
|
|
template <
|
|
|
|
|
class U, detail::enable_from_other<T, U, U &&> * = nullptr,
|
|
|
|
|
detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr>
|
|
|
|
|
explicit optional(optional<U> &&rhs) {
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::move(*rhs));
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 19:41:18 +01:00
|
|
|
/// Destroys the stored value if there is one.
|
2017-10-21 19:04:41 +01:00
|
|
|
~optional() = default;
|
|
|
|
|
|
|
|
|
|
/// Assignment to empty.
|
|
|
|
|
///
|
|
|
|
|
/// Destroys the current value if there is one.
|
|
|
|
|
optional &operator=(nullopt_t) noexcept {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
2017-10-21 21:38:17 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO conditionally delete, check exception guarantee
|
|
|
|
|
/// Copy assignment.
|
|
|
|
|
///
|
2017-10-24 15:07:29 +01:00
|
|
|
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
|
|
|
|
/// value in `*this`.
|
2017-10-21 19:04:41 +01:00
|
|
|
optional &operator=(const optional &rhs) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
this->m_value = rhs.m_value;
|
|
|
|
|
} else {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
new (std::addressof(this->m_value)) T(rhs.m_value);
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
}
|
2017-10-21 21:29:29 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO conditionally delete, check exception guarantee
|
|
|
|
|
/// Move assignment.
|
|
|
|
|
///
|
2017-10-24 15:07:29 +01:00
|
|
|
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
|
|
|
|
|
/// value in `*this`.
|
2017-10-21 19:04:41 +01:00
|
|
|
optional &operator=(optional &&rhs) noexcept(
|
|
|
|
|
std::is_nothrow_move_assignable<T>::value
|
|
|
|
|
&&std::is_nothrow_move_constructible<T>::value) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
this->m_value = std::move(rhs.m_value);
|
|
|
|
|
} else {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::move(rhs.m_value));
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
}
|
2017-10-21 21:29:29 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO conditionally delete, check exception guarantee
|
2017-10-24 15:07:29 +01:00
|
|
|
/// Assigns the stored value from `u`, destroying the old value if there was
|
|
|
|
|
/// one. \synopsis optional &operator=(U &&u);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class U = T, detail::enable_assign_forward<T, U> * = nullptr>
|
|
|
|
|
optional &operator=(U &&u) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
this->m_value = std::forward<U>(u);
|
|
|
|
|
} else {
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::forward<U>(u));
|
|
|
|
|
this->m_has_value = true;
|
|
|
|
|
}
|
2017-10-21 21:29:29 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO check exception guarantee
|
|
|
|
|
/// Converting copy assignment operator.
|
|
|
|
|
///
|
2017-10-24 15:07:29 +01:00
|
|
|
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
|
|
|
|
/// value in `*this`. \synopsis optional &operator=(const optional<U> & rhs);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class U,
|
|
|
|
|
detail::enable_assign_from_other<T, U, const U &> * = nullptr>
|
|
|
|
|
optional &operator=(const optional<U> &rhs) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
if (rhs.has_value()) {
|
2017-10-21 21:24:34 +01:00
|
|
|
this->m_value = *rhs;
|
2017-10-21 19:04:41 +01:00
|
|
|
} else {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rhs.has_value()) {
|
2017-10-21 21:24:34 +01:00
|
|
|
new (std::addressof(this->m_value)) T(*rhs);
|
2017-10-21 19:04:41 +01:00
|
|
|
this->m_has_value = true;
|
|
|
|
|
}
|
2017-10-21 21:29:29 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO check exception guarantee
|
|
|
|
|
/// Converting move assignment operator.
|
|
|
|
|
///
|
2017-10-24 15:07:29 +01:00
|
|
|
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
|
|
|
|
|
/// value in `*this`. \synopsis optional &operator=(optional<U> && rhs);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class U, detail::enable_assign_from_other<T, U, U> * = nullptr>
|
|
|
|
|
optional &operator=(optional<U> &&rhs) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
if (rhs.has_value()) {
|
2017-10-21 21:24:34 +01:00
|
|
|
this->m_value = std::move(*rhs);
|
2017-10-21 19:04:41 +01:00
|
|
|
} else {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rhs.has_value()) {
|
2017-10-21 21:24:34 +01:00
|
|
|
new (std::addressof(this->m_value)) T(std::move(*rhs));
|
2017-10-21 19:04:41 +01:00
|
|
|
this->m_has_value = true;
|
|
|
|
|
}
|
2017-10-21 21:29:29 +01:00
|
|
|
|
|
|
|
|
return *this;
|
2017-10-21 19:04:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Constructs the value in-place, destroying the current one if there is one.
|
|
|
|
|
/// \group emplace
|
|
|
|
|
template <class... Args> T &emplace(Args &&... args) {
|
|
|
|
|
static_assert(std::is_constructible<T, Args &&...>::value,
|
|
|
|
|
"T must be constructible with Args");
|
|
|
|
|
|
|
|
|
|
*this = nullopt;
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::forward<Args>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group emplace
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \synopsis template <class U, class... Args>\nT&
|
|
|
|
|
/// emplace(std::initializer_list<U> il, Args &&... args);
|
2017-10-21 19:04:41 +01:00
|
|
|
template <class U, class... Args>
|
|
|
|
|
detail::enable_if_t<
|
|
|
|
|
std::is_constructible<T, std::initializer_list<U> &, Args &&...>::value,
|
|
|
|
|
T &>
|
|
|
|
|
emplace(std::initializer_list<U> il, Args &&... args) {
|
|
|
|
|
*this = nullopt;
|
|
|
|
|
new (std::addressof(this->m_value)) T(il, 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.
|
2017-10-24 15:07:29 +01:00
|
|
|
/// If one has a value, it is moved to the other and the movee is left
|
|
|
|
|
/// valueless.
|
2017-10-21 19:04:41 +01:00
|
|
|
void
|
|
|
|
|
swap(optional &rhs) noexcept(std::is_nothrow_move_constructible<T>::value
|
|
|
|
|
&&detail::is_nothrow_swappable<T>::value) {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
if (rhs.has_value()) {
|
|
|
|
|
using std::swap;
|
|
|
|
|
swap(**this, *rhs);
|
|
|
|
|
} else {
|
|
|
|
|
new (&rhs.m_value) T(std::move(this->m_value));
|
|
|
|
|
this->m_value.T::~T();
|
|
|
|
|
}
|
|
|
|
|
} else if (rhs.has_value()) {
|
|
|
|
|
new (std::addressof(this->m_value)) T(std::move(rhs.m_value));
|
|
|
|
|
rhs.m_value.T::~T();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \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 std::addressof(this->m_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \group pointer
|
|
|
|
|
/// \synopsis constexpr T *operator->();
|
|
|
|
|
TL_OPTIONAL_11_CONSTEXPR T *operator->() {
|
|
|
|
|
return std::addressof(this->m_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// \returns the stored value
|
|
|
|
|
/// \requires a value is stored
|
|
|
|
|
/// \group deref
|
|
|
|
|
/// \synopsis constexpr T &operator*();
|
|
|
|
|
TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; }
|
|
|
|
|
|
|
|
|
|
/// \group deref
|
|
|
|
|
/// \synopsis constexpr const T &operator*() const;
|
|
|
|
|
constexpr const T &operator*() const & { return this->m_value; }
|
|
|
|
|
|
|
|
|
|
/// \exclude
|
|
|
|
|
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && {
|
|
|
|
|
return std::move(this->m_value);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
|
|
|
|
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 19:04:41 +01:00
|
|
|
|
|
|
|
|
/// \returns whether or not the optional has a value
|
|
|
|
|
/// \group has_value
|
|
|
|
|
constexpr bool has_value() const noexcept { return this->m_has_value; }
|
|
|
|
|
|
|
|
|
|
/// \group has_value
|
|
|
|
|
constexpr explicit operator bool() const noexcept {
|
|
|
|
|
return this->m_has_value;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \returns the contained value if there is one, otherwise throws
|
|
|
|
|
/// [bad_optional_access] \group value \synopsis constexpr T &value();
|
2017-10-21 19:04:41 +01:00
|
|
|
TL_OPTIONAL_11_CONSTEXPR T &value() & {
|
|
|
|
|
if (has_value())
|
|
|
|
|
return this->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 this->m_value;
|
|
|
|
|
throw bad_optional_access();
|
|
|
|
|
}
|
|
|
|
|
/// \exclude
|
|
|
|
|
TL_OPTIONAL_11_CONSTEXPR T &&value() && {
|
|
|
|
|
if (has_value())
|
|
|
|
|
return std::move(this->m_value);
|
|
|
|
|
throw bad_optional_access();
|
|
|
|
|
}
|
2017-10-21 22:31:42 +01:00
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
2017-10-21 19:04:41 +01:00
|
|
|
/// \exclude
|
|
|
|
|
constexpr const T &&value() const && {
|
|
|
|
|
if (has_value())
|
|
|
|
|
return std::move(this->m_value);
|
|
|
|
|
throw bad_optional_access();
|
|
|
|
|
}
|
2017-10-24 15:07:29 +01:00
|
|
|
#endif
|
2017-10-21 19:04:41 +01:00
|
|
|
|
|
|
|
|
/// \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 {
|
|
|
|
|
if (has_value()) {
|
|
|
|
|
this->m_value.~T();
|
|
|
|
|
this->m_has_value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// \group relop
|
|
|
|
|
/// \brief Compares two optional objects
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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.
|
2017-10-21 19:04:41 +01:00
|
|
|
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.
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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.
|
2017-10-21 19:04:41 +01:00
|
|
|
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)...);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 20:57:56 +01:00
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
|
template <class T> optional(T)->optional<T>;
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-24 15:07:29 +01:00
|
|
|
/// \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>
|
2017-10-24 15:46:07 +01:00
|
|
|
constexpr auto map_impl(Opt &&opt, F &&f) {
|
2017-10-24 15:07:29 +01:00
|
|
|
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>
|
|
|
|
|
|
2017-10-24 15:46:07 +01:00
|
|
|
constexpr auto map_impl(Opt &&opt, F &&f) -> optional<Ret> {
|
2017-10-24 15:07:29 +01:00
|
|
|
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
|
|
|
|
|
|
2017-10-21 19:04:41 +01:00
|
|
|
} // namespace tl
|
|
|
|
|
|
|
|
|
|
namespace std {
|
|
|
|
|
// TODO SFINAE
|
|
|
|
|
template <class T> struct hash<tl::optional<T>> {
|
|
|
|
|
::std::size_t operator()(const tl::optional<T> &o) const {
|
|
|
|
|
if (!o.has_value())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return std::hash<tl::detail::remove_const_t<T>>()(*o);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
} // namespace std
|
2017-10-24 09:01:24 +01:00
|
|
|
|
|
|
|
|
#endif
|