This commit is contained in:
Simon Brand
2017-10-24 15:32:22 +01:00
parent 98f34bed66
commit 0df06afe8d
2 changed files with 74 additions and 10 deletions

View File

@ -337,6 +337,60 @@ 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:
#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
/// \group and_then /// \group and_then
/// Carries out some operation which returns an optional on the stored object /// Carries out some operation which returns an optional on the stored object
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())` /// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
@ -347,8 +401,8 @@ public:
/// is returned. \group and_then \synopsis template <class F>\nconstexpr auto /// is returned. \group and_then \synopsis template <class F>\nconstexpr auto
/// and_then(F &&f) &; /// 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 &>;
static_assert(detail::is_optional<result>::value, static_assert(detail::is_optional<result>::value,
"F must return an optional"); "F must return an optional");
@ -359,8 +413,8 @@ public:
/// \group and_then /// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; /// \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 &&>;
static_assert(detail::is_optional<result>::value, static_assert(detail::is_optional<result>::value,
"F must return an optional"); "F must return an optional");
@ -371,8 +425,8 @@ public:
/// \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>
constexpr detail::invoke_result_t<F, T> and_then(F &&f) const & { constexpr detail::invoke_result_t<F, const T &> and_then(F &&f) const & {
using result = detail::invoke_result_t<F, T>; using result = detail::invoke_result_t<F, const T &>;
static_assert(detail::is_optional<result>::value, static_assert(detail::is_optional<result>::value,
"F must return an optional"); "F must return an optional");
@ -384,8 +438,8 @@ public:
/// \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>
constexpr detail::invoke_result_t<F, T> and_then(F &&f) const && { constexpr detail::invoke_result_t<F, const T &&> and_then(F &&f) const && {
using result = detail::invoke_result_t<F, T>; using result = detail::invoke_result_t<F, const T &&>;
static_assert(detail::is_optional<result>::value, static_assert(detail::is_optional<result>::value,
"F must return an optional"); "F must return an optional");
@ -393,6 +447,7 @@ public:
: result(nullopt); : result(nullopt);
} }
#endif #endif
#endif
#ifdef TL_OPTIONAL_CXX14 #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.

View File

@ -335,11 +335,20 @@ TEST_CASE("Monadic operations", "[monadic]") {
}; };
#ifdef TL_OPTIONAL_CXX14 #ifdef TL_OPTIONAL_CXX14
// Reported by Mark Papadakis SECTION("Issue #1") {
SECTION("map const correctness") {
tl::optional<foo> f = foo{}; tl::optional<foo> f = foo{};
auto l = [](auto &&x) { x.non_const(); }; auto l = [](auto &&x) { x.non_const(); };
f.map(l); f.map(l);
} }
#endif #endif
struct overloaded {
tl::optional<int> operator()(foo &) { return 0; }
tl::optional<std::string> operator()(const foo &) { return ""; }
};
SECTION("Issue #2") {
tl::optional<foo> f = foo{};
auto x = f.and_then(overloaded{});
}
}; };