diff --git a/tests/extensions.cpp b/tests/extensions.cpp index 6712b3e..0f9827d 100644 --- a/tests/extensions.cpp +++ b/tests/extensions.cpp @@ -125,6 +125,11 @@ TEST_CASE("Monadic operations", "[monadic]") { auto o38r = o38.map([](int &i) -> const int & { return i; }); REQUIRE(o38r); REQUIRE(*o38r == 42); + + int i = 42; + tl::optional o39 = i; + o39.map([](int& x){x = 12;}); + REQUIRE(i == 12); } SECTION("map constexpr") { diff --git a/tl/optional.hpp b/tl/optional.hpp index 0e7ab9e..1bc288e 100644 --- a/tl/optional.hpp +++ b/tl/optional.hpp @@ -1,3 +1,4 @@ + /// // optional - An implementation of std::optional with extensions // Written in 2017 by Simon Brand (@TartanLlama) @@ -1597,6 +1598,59 @@ inline constexpr optional make_optional(std::initializer_list il, template optional(T)->optional; #endif +/// \exclude +namespace detail { +#ifdef TL_OPTIONAL_CX14 +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_impl(Opt &&opt, F &&f) { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional>(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto map_impl(Opt &&opt, F &&f) { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return monostate{}; + } + + return optional(nullopt); +} +#else +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto map_impl(Opt &&opt, F &&f) -> optional> { + return opt.has_value() + ? detail::invoke(std::forward(f), *std::forward(opt)) + : optional>(nullopt); +} + +template (), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto map_impl(Opt &&opt, F &&f) -> optional { + if (opt.has_value()) { + detail::invoke(std::forward(f), *std::forward(opt)); + return monostate{}; + } + + return nullopt; +} +#endif +} // namespace detail + /// Specialization for when `T` is a reference. `optional` acts similarly /// to a `T*`, but provides more operations and shows intent more clearly. /// @@ -1752,25 +1806,25 @@ public: /// \group map /// \synopsis template constexpr auto map(F &&f) &; template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { - return map_impl(*this, std::forward(f)); + return detail::map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) &&; template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { - return map_impl(std::move(*this), std::forward(f)); + return detail::map_impl(std::move(*this), std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&; template constexpr auto map(F &&f) const & { - return map_impl(*this, std::forward(f)); + return detail::map_impl(*this, std::forward(f)); } /// \group map /// \synopsis template constexpr auto map(F &&f) const&&; template constexpr auto map(F &&f) const && { - return map_impl(std::move(*this), std::forward(f)); + return detail::map_impl(std::move(*this), std::forward(f)); } #else /// \brief Carries out some operation on the stored object if there is one. @@ -1786,7 +1840,7 @@ public: TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), std::declval())) map(F &&f) & { - return map_impl(*this, std::forward(f)); + return detail::map_impl(*this, std::forward(f)); } /// \group map @@ -1795,7 +1849,7 @@ public: TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), std::declval())) map(F &&f) && { - return map_impl(std::move(*this), std::forward(f)); + return detail::map_impl(std::move(*this), std::forward(f)); } /// \group map @@ -1804,7 +1858,7 @@ public: constexpr decltype(map_impl(std::declval(), std::declval())) map(F &&f) const & { - return map_impl(*this, std::forward(f)); + return detail::map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR @@ -1814,7 +1868,7 @@ public: constexpr decltype(map_impl(std::declval(), std::declval())) map(F &&f) const && { - return map_impl(std::move(*this), std::forward(f)); + return detail::map_impl(std::move(*this), std::forward(f)); } #endif #endif @@ -2239,58 +2293,7 @@ private: T *m_value; }; // namespace tl -/// \exclude -namespace detail { -#ifdef TL_OPTIONAL_CX14 -template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> -constexpr auto map_impl(Opt &&opt, F &&f) { - return opt.has_value() - ? detail::invoke(std::forward(f), *std::forward(opt)) - : optional>(nullopt); -} -template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> -auto map_impl(Opt &&opt, F &&f) { - if (opt.has_value()) { - detail::invoke(std::forward(f), *std::forward(opt)); - return monostate{}; - } - - return optional(nullopt); -} -#else -template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> - -constexpr auto map_impl(Opt &&opt, F &&f) -> optional> { - return opt.has_value() - ? detail::invoke(std::forward(f), *std::forward(opt)) - : optional>(nullopt); -} - -template (), - *std::declval())), - detail::enable_if_t::value> * = nullptr> - -auto map_impl(Opt &&opt, F &&f) -> optional { - if (opt.has_value()) { - detail::invoke(std::forward(f), *std::forward(opt)); - return monostate{}; - } - - return nullopt; -} -#endif -} // namespace detail } // namespace tl