diff --git a/optional.hpp b/optional.hpp index 9f768b2..313d5fb 100644 --- a/optional.hpp +++ b/optional.hpp @@ -337,6 +337,9 @@ template class optional : private detail::optional_storage_base { using base = detail::optional_storage_base; public: +// 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 #ifdef TL_OPTIONAL_CXX14 /// \group and_then /// Carries out some operation which returns an optional on the stored object @@ -456,23 +459,21 @@ public: /// `*this` is empty, otherwise an `optional` is constructed from the /// return value of `std::invoke(std::forward(f), value())` and is /// returned. \group map \synopsis template auto map(F &&f) &; - template auto map(F &&f) & { + template constexpr auto map(F &&f) & { return map_impl(*this, std::forward(f)); } - template auto map(F &&f) && { + template constexpr auto map(F &&f) && { return map_impl(std::move(*this), std::forward(f)); } - template auto map(F &&f) const & { + template constexpr auto map(F &&f) const & { return map_impl(*this, std::forward(f)); } -#ifndef TL_OPTIONAL_NO_CONSTRR - template auto map(F &&f) const && { + template constexpr auto map(F &&f) const && { return map_impl(std::move(*this), std::forward(f)); } -#endif #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), @@ -481,26 +482,30 @@ public: /// return value of `std::invoke(std::forward(f), value())` and is /// returned. \group map \synopsis template auto map(F &&f) &; template - decltype(map_impl(std::declval(), std::declval())) + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) map(F &&f) & { return map_impl(*this, std::forward(f)); } template - decltype(map_impl(std::declval(), std::declval())) + TL_OPTIONAL_11_CONSTEXPR decltype(map_impl(std::declval(), + std::declval())) map(F &&f) && { return map_impl(std::move(*this), std::forward(f)); } template - decltype(map_impl(std::declval(), std::declval())) + constexpr decltype(map_impl(std::declval(), + std::declval())) map(F &&f) const & { return map_impl(*this, std::forward(f)); } #ifndef TL_OPTIONAL_NO_CONSTRR template - decltype(map_impl(std::declval(), std::declval())) + constexpr decltype(map_impl(std::declval(), + std::declval())) map(F &&f) const && { return map_impl(std::move(*this), std::forward(f)); } @@ -1316,7 +1321,7 @@ template (), *std::declval())), detail::enable_if_t::value> * = nullptr> -auto map_impl(Opt &&opt, F &&f) { +constexpr auto map_impl(Opt &&opt, F &&f) { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); @@ -1340,7 +1345,7 @@ template ())), detail::enable_if_t::value> * = nullptr> -auto map_impl(Opt &&opt, F &&f) -> optional { +constexpr auto map_impl(Opt &&opt, F &&f) -> optional { return opt.has_value() ? detail::invoke(std::forward(f), *std::forward(opt)) : optional(nullopt); diff --git a/tests/extensions.cpp b/tests/extensions.cpp index 71a5e8f..0ccb5f3 100644 --- a/tests/extensions.cpp +++ b/tests/extensions.cpp @@ -128,34 +128,16 @@ TEST_CASE("Monadic operations", "[monadic]") { constexpr auto o16r = o16.map(get_int); STATIC_REQUIRE(*o16r == 42); - constexpr tl::optional 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 o20 = 42; constexpr auto o20r = std::move(o20).map(get_int); STATIC_REQUIRE(*o20r == 42); - constexpr tl::optional o22 = 42; - constexpr auto o22r = std::move(o22).map(opt_int); - STATIC_REQUIRE(*o22r == 42); - constexpr tl::optional o32 = tl::nullopt; constexpr auto o32r = o32.map(get_int); STATIC_REQUIRE(!o32r); - - constexpr tl::optional o34 = tl::nullopt; - constexpr auto o34r = o34.map(opt_int); - STATIC_REQUIRE(!o34r); - constexpr tl::optional o36 = tl::nullopt; constexpr auto o36r = std::move(o36).map(get_int); STATIC_REQUIRE(!o36r); - - constexpr tl::optional o38 = tl::nullopt; - constexpr auto o38r = std::move(o38).map(opt_int); - STATIC_REQUIRE(!o38r); #endif }