diff --git a/CMakeLists.txt b/CMakeLists.txt
index a9394b3..2deb4fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tests/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/in_place.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/relops.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/observers.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/tests/monadic.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tests/extensions.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/constexpr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/nullopt.cpp)
diff --git a/docs/index.md b/docs/index.md
index aab5c61..993f68f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -177,16 +177,16 @@ public:
U map_or(F&& f, U&& u) const &&;
template <class F, class U>
- U map_or_else(F&& f, U&& u) &;
+ auto map_or_else(F &&f, U &&u) &;
template <class F, class U>
- U map_or_else(F&& f, U&& u) &&;
+ auto map_or_else(F &&f, U &&u) &&;
template <class F, class U>
- U map_or_else(F&& f, U&& u) const &;
+ auto map_or_else(F &&f, U &&u) const &;
template <class F, class U>
- U map_or_else(F&& f, U&& u) const &&;
+ auto map_or_else(F &&f, U &&u) const &&;
template <class U>
- constexpr optional<U> conjunction(U&& u) const;
+ constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const;
constexpr optional disjunction(const optional& rhs) &;
constexpr optional disjunction(const optional& rhs) const &;
@@ -333,16 +333,16 @@ If there is a value stored, then `f` is called with `**this` and the value is re
### Function template `tl::optional::map_or_else`
(1) template <class F, class U>
- U map_or_else(F&& f, U&& u) &;
+ auto map_or_else(F &&f, U &&u) &;
(2) template <class F, class U>
- U map_or_else(F&& f, U&& u) &&;
+ auto map_or_else(F &&f, U &&u) &&;
(3) template <class F, class U>
- U map_or_else(F&& f, U&& u) const &;
+ auto map_or_else(F &&f, U &&u) const &;
(4) template <class F, class U>
- U map_or_else(F&& f, U&& u) const &&;
+ auto map_or_else(F &&f, U &&u) const &&;
Maps the stored value with `f` if there is one, otherwise calls `u` and returns the result.
@@ -351,7 +351,7 @@ If there is a value stored, then `f` is called with `**this` and the value is re
### Function template `tl::optional::conjunction`
template <class U>
-constexpr optional<U> conjunction(U&& u) const;
+constexpr optional<typename std::decay<U>::type> conjunction(U&& u) const;
*Returns*: `u` if `*this` has a value, otherwise an empty optional.
diff --git a/optional.hpp b/optional.hpp
index 8636761..9238f0e 100644
--- a/optional.hpp
+++ b/optional.hpp
@@ -683,32 +683,42 @@ public:
/// \details If there is a value stored, then `f` is called with `**this` and the value is returned.
/// Otherwise `std::forward(u)()` is returned.
/// \group map_or_else
- template U map_or_else(F &&f, U &&u) & {
+ /// \synopsis template \nauto map_or_else(F &&f, U &&u) &;
+ template
+ detail::invoke_result_t map_or_else(F &&f, U &&u) & {
return has_value() ? detail::invoke(std::forward(f), **this)
: std::forward(u)();
}
/// \group map_or_else
- template U map_or_else(F &&f, U &&u) && {
+ /// \synopsis template \nauto map_or_else(F &&f, U &&u) &&;
+ template
+ detail::invoke_result_t map_or_else(F &&f, U &&u) && {
return has_value() ? detail::invoke(std::forward(f), std::move(**this))
: std::forward(u)();
}
/// \group map_or_else
- template U map_or_else(F &&f, U &&u) const & {
+ /// \synopsis template \nauto map_or_else(F &&f, U &&u) const &;
+ template
+ detail::invoke_result_t map_or_else(F &&f, U &&u) const & {
return has_value() ? detail::invoke(std::forward(f), **this)
: std::forward(u)();
}
/// \group map_or_else
- template U map_or_else(F &&f, U &&u) const && {
+ /// \synopsis template \nauto map_or_else(F &&f, U &&u) const &&;
+ template
+ detail::invoke_result_t map_or_else(F &&f, U &&u) const && {
return has_value() ? detail::invoke(std::forward(f), std::move(**this))
: std::forward(u)();
}
/// \returns `u` if `*this` has a value, otherwise an empty optional.
- template constexpr optional conjunction (U &&u) const {
- return has_value() ? u : nullopt;
+ template
+ constexpr optional::type> conjunction (U &&u) const {
+ using result = optional>;
+ return has_value() ? result{u} : result{nullopt};
}
/// \returns `rhs` if `*this` is empty, otherwise the current value.
diff --git a/tests/monadic.cpp b/tests/extensions.cpp
similarity index 86%
rename from tests/monadic.cpp
rename to tests/extensions.cpp
index 522bdf6..018bbc2 100644
--- a/tests/monadic.cpp
+++ b/tests/extensions.cpp
@@ -1,5 +1,6 @@
#include "catch.hpp"
#include "optional.hpp"
+#include
#define TOKENPASTE(x, y) x##y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
@@ -339,7 +340,62 @@ SECTION("constexpr and_then") {
}
SECTION("or else") {
- //TODO
+ tl::optional o1 = 42;
+ REQUIRE(*(o1.or_else([] { return tl::make_optional(13); })) == 42);
+
+ tl::optional o2;
+ REQUIRE(*(o2.or_else([] { return tl::make_optional(13); })) == 13);
+}
+
+SECTION("disjunction") {
+ tl::optional o1 = 42;
+ tl::optional o2 = 12;
+ tl::optional o3;
+
+ REQUIRE(*o1.disjunction(o2) == 42);
+ REQUIRE(*o1.disjunction(o3) == 42);
+ REQUIRE(*o2.disjunction(o1) == 12);
+ REQUIRE(*o2.disjunction(o3) == 12);
+ REQUIRE(*o3.disjunction(o1) == 42);
+ REQUIRE(*o3.disjunction(o2) == 12);
+}
+
+SECTION("conjunction") {
+ tl::optional o1 = 42;
+ REQUIRE(*o1.conjunction(42.0) == 42.0);
+ REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
+ REQUIRE(!o1.conjunction(tl::nullopt));
+
+ tl::optional o2;
+ REQUIRE(!o2.conjunction(42.0));
+ REQUIRE(!o2.conjunction(std::string{"hello"}));
+ REQUIRE(!o2.conjunction(tl::nullopt));
+}
+
+SECTION("map_or") {
+ tl::optional o1 = 21;
+ REQUIRE((o1.map_or([](auto x) { return x * 2; }, 13)) == 42);
+
+ tl::optional o2;
+ REQUIRE((o2.map_or([](auto x) { return x * 2; }, 13)) == 13);
+}
+
+SECTION("map_or_else") {
+ tl::optional o1 = 21;
+ REQUIRE((o1.map_or_else([](auto x) { return x * 2; }, []{return 13;})) == 42);
+
+ tl::optional o2;
+ REQUIRE((o2.map_or_else([](auto x) { return x * 2; }, []{return 13;})) == 13);
+}
+
+SECTION("take") {
+ tl::optional o1 = 42;
+ REQUIRE(*o1.take() == 42);
+ REQUIRE(!o1);
+
+ tl::optional o2;
+ REQUIRE(!o2.take());
+ REQUIRE(!o2);
}
}
;