From 0df06afe8dc385f970038aa18876b8d573108983 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Tue, 24 Oct 2017 15:32:22 +0100 Subject: [PATCH] Fix #2 --- optional.hpp | 71 +++++++++++++++++++++++++++++++++++++++----- tests/extensions.cpp | 13 ++++++-- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/optional.hpp b/optional.hpp index 3830f9a..9f768b2 100644 --- a/optional.hpp +++ b/optional.hpp @@ -337,6 +337,60 @@ template class optional : private detail::optional_storage_base { using base = detail::optional_storage_base; 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), value())` + /// returns a `std::optional` for some `U`. \returns Let `U` be the result + /// of `std::invoke(std::forward(f), value())`. Returns a + /// `std::optional`. The return value is empty if `*this` is empty, + /// otherwise the return value of `std::invoke(std::forward(f), value())` + /// is returned. \group and_then \synopsis template \nconstexpr auto + /// and_then(F &&f) &; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) &&; + template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } + + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &; + template constexpr auto and_then(F &&f) const & { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), **this) + : result(nullopt); + } + +#ifndef TL_OPTIONAL_NO_CONSTRR + /// \group and_then + /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; + template constexpr auto and_then(F &&f) const && { + using result = detail::invoke_result_t; + static_assert(detail::is_optional::value, + "F must return an optional"); + + return has_value() ? detail::invoke(std::forward(f), std::move(**this)) + : result(nullopt); + } +#endif +#else /// \group and_then /// Carries out some operation which returns an optional on the stored object /// if there is one. \requires `std::invoke(std::forward(f), value())` @@ -347,8 +401,8 @@ public: /// is returned. \group and_then \synopsis template \nconstexpr auto /// and_then(F &&f) &; template - TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { - using result = detail::invoke_result_t; + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { + using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); @@ -359,8 +413,8 @@ public: /// \group and_then /// \synopsis template \nconstexpr auto and_then(F &&f) &&; template - TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { - using result = detail::invoke_result_t; + TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { + using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); @@ -371,8 +425,8 @@ public: /// \group and_then /// \synopsis template \nconstexpr auto and_then(F &&f) const &; template - constexpr detail::invoke_result_t and_then(F &&f) const & { - using result = detail::invoke_result_t; + constexpr detail::invoke_result_t and_then(F &&f) const & { + using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); @@ -384,8 +438,8 @@ public: /// \group and_then /// \synopsis template \nconstexpr auto and_then(F &&f) const &&; template - constexpr detail::invoke_result_t and_then(F &&f) const && { - using result = detail::invoke_result_t; + constexpr detail::invoke_result_t and_then(F &&f) const && { + using result = detail::invoke_result_t; static_assert(detail::is_optional::value, "F must return an optional"); @@ -393,6 +447,7 @@ public: : result(nullopt); } #endif +#endif #ifdef TL_OPTIONAL_CXX14 /// \brief Carries out some operation on the stored object if there is one. diff --git a/tests/extensions.cpp b/tests/extensions.cpp index 2ef9bce..71a5e8f 100644 --- a/tests/extensions.cpp +++ b/tests/extensions.cpp @@ -335,11 +335,20 @@ TEST_CASE("Monadic operations", "[monadic]") { }; #ifdef TL_OPTIONAL_CXX14 - // Reported by Mark Papadakis - SECTION("map const correctness") { + SECTION("Issue #1") { tl::optional f = foo{}; auto l = [](auto &&x) { x.non_const(); }; f.map(l); } #endif + + struct overloaded { + tl::optional operator()(foo &) { return 0; } + tl::optional operator()(const foo &) { return ""; } + }; + + SECTION("Issue #2") { + tl::optional f = foo{}; + auto x = f.and_then(overloaded{}); + } };