forked from TartanLlama/optional
C++11 support
This commit is contained in:
@ -15,9 +15,9 @@ set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tests/main.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/constexpr.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests/constexpr.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests/nullopt.cpp)
|
||||
|
||||
|
||||
add_executable(tests ${TEST_SOURCES})
|
||||
target_link_libraries(tests Catch)
|
||||
set_property(TARGET tests PROPERTY CXX_STANDARD 14)
|
||||
set_property(TARGET tests PROPERTY CXX_STANDARD 11)
|
||||
|
186
optional.hpp
186
optional.hpp
@ -17,6 +17,12 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus == 201103L
|
||||
#define TL_OPTIONAL_11_CONSTEXPR
|
||||
#else
|
||||
#define TL_OPTIONAL_11_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
namespace tl {
|
||||
template <class T> class optional;
|
||||
class monostate {};
|
||||
@ -83,7 +89,7 @@ constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
||||
|
||||
template <
|
||||
typename Fn, typename... Args,
|
||||
std::enable_if_t<!std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0>
|
||||
enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}, int> = 0>
|
||||
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
||||
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
||||
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
||||
@ -108,12 +114,11 @@ using invoke_result_t = typename invoke_result<F, Us...>::type;
|
||||
template <class U>
|
||||
using fixup_void = conditional_t<std::is_void<U>::value, monostate, U>;
|
||||
|
||||
// TODO check if we need std::invoke_result here
|
||||
template <class F, class U> struct get_invoke_optional_ret {
|
||||
using type = result_of_t<
|
||||
using type = invoke_result_t<
|
||||
conditional_t<std::is_lvalue_reference<F>::value,
|
||||
typename std::remove_reference_t<F>::value_type &,
|
||||
typename std::remove_reference_t<F>::value_type &&>(U)>;
|
||||
typename remove_reference_t<F>::value_type &,
|
||||
typename remove_reference_t<F>::value_type &&>, U>;
|
||||
};
|
||||
|
||||
template <class F, class U>
|
||||
@ -498,7 +503,7 @@ public:
|
||||
// [optional.ctor], constructors
|
||||
constexpr optional() noexcept = default;
|
||||
constexpr optional(nullopt_t) noexcept {};
|
||||
constexpr optional(const optional &rhs) {
|
||||
TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) {
|
||||
if (rhs.has_value()) {
|
||||
this->m_has_value = true;
|
||||
new (std::addressof(this->m_value)) T(*rhs);
|
||||
@ -506,7 +511,7 @@ public:
|
||||
}
|
||||
|
||||
// TODO conditionally disable
|
||||
constexpr optional(optional &&rhs) noexcept(
|
||||
TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<T>::value) {
|
||||
if (rhs.has_value()) {
|
||||
this->m_has_value = true;
|
||||
@ -519,7 +524,7 @@ public:
|
||||
Args &&... args)
|
||||
: base(in_place, std::forward<Args>(args)...) {}
|
||||
template <class U, class... Args>
|
||||
constexpr explicit optional(
|
||||
TL_OPTIONAL_11_CONSTEXPR explicit optional(
|
||||
detail::enable_if_t<std::is_constructible<T, std::initializer_list<U> &,
|
||||
Args &&...>::value,
|
||||
in_place_t>,
|
||||
@ -706,26 +711,26 @@ public:
|
||||
constexpr const T *operator->() const {
|
||||
return std::addressof(this->m_value);
|
||||
}
|
||||
constexpr T *operator->() { return std::addressof(this->m_value); }
|
||||
TL_OPTIONAL_11_CONSTEXPR T *operator->() { return std::addressof(this->m_value); }
|
||||
constexpr const T &operator*() const & { return this->m_value; }
|
||||
constexpr T &operator*() & { return this->m_value; }
|
||||
constexpr T &&operator*() && { return std::move(this->m_value); }
|
||||
TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; }
|
||||
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(this->m_value); }
|
||||
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return this->m_has_value;
|
||||
}
|
||||
constexpr bool has_value() const noexcept { return this->m_has_value; }
|
||||
constexpr const T &value() const & {
|
||||
TL_OPTIONAL_11_CONSTEXPR const T &value() const & {
|
||||
if (has_value())
|
||||
return this->m_value;
|
||||
throw bad_optional_access();
|
||||
}
|
||||
constexpr T &value() & {
|
||||
TL_OPTIONAL_11_CONSTEXPR T &value() & {
|
||||
if (has_value())
|
||||
return this->m_value;
|
||||
throw bad_optional_access();
|
||||
}
|
||||
constexpr T &&value() && {
|
||||
TL_OPTIONAL_11_CONSTEXPR T &&value() && {
|
||||
if (has_value())
|
||||
return std::move(this->m_value);
|
||||
throw bad_optional_access();
|
||||
@ -756,25 +761,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <class F> constexpr detail::invoke_result_t<F, T> bind(F &&f) & {
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T> bind(F &&f) & {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
return detail::invoke(std::forward<F>(f), value());
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
|
||||
}
|
||||
|
||||
template <class F> constexpr detail::invoke_result_t<F, T> bind(F &&f) && {
|
||||
template <class F> TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T> bind(F &&f) && {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
return detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@ -783,10 +783,7 @@ public:
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
return detail::invoke(std::forward<F>(f), value());
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), **this) : result(nullopt);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@ -795,14 +792,11 @@ public:
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
return detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return has_value() ? detail::invoke(std::forward<F>(f), std::move(**this)) : result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, class E>
|
||||
constexpr detail::invoke_result_t<F, T> bind(F &&f, E &&e) & {
|
||||
detail::invoke_result_t<F, T> bind(F &&f, E &&e) & {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
@ -810,14 +804,14 @@ public:
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
auto ret = detail::invoke(std::forward<F>(f), value());
|
||||
auto ret = detail::invoke(std::forward<F>(f), **this);
|
||||
if (!ret)
|
||||
detail::invoke(e);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class F, class E>
|
||||
constexpr detail::invoke_result_t<F, T> bind(F &&f, E &&e) && {
|
||||
detail::invoke_result_t<F, T> bind(F &&f, E &&e) && {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
@ -825,14 +819,14 @@ public:
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
auto ret = detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
auto ret = detail::invoke(std::forward<F>(f), std::move(**this));
|
||||
if (!ret)
|
||||
detail::invoke(e);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class F, class E>
|
||||
constexpr detail::invoke_result_t<F, T> bind(F &&f, E &&e) const & {
|
||||
detail::invoke_result_t<F, T> bind(F &&f, E &&e) const & {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
@ -840,14 +834,14 @@ public:
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
auto ret = detail::invoke(std::forward<F>(f), value());
|
||||
auto ret = detail::invoke(std::forward<F>(f), **this);
|
||||
if (!ret)
|
||||
detail::invoke(e);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class F, class E>
|
||||
constexpr detail::invoke_result_t<F, T> bind(F &&f, E &&e) const && {
|
||||
detail::invoke_result_t<F, T> bind(F &&f, E &&e) const && {
|
||||
using result = detail::invoke_result_t<F, T>;
|
||||
static_assert(detail::is_optional<result>::value,
|
||||
"F must return an optional");
|
||||
@ -855,7 +849,7 @@ public:
|
||||
if (!has_value())
|
||||
return result(nullopt);
|
||||
|
||||
auto ret = detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
auto ret = detail::invoke(std::forward<F>(f), std::move(**this));
|
||||
if (!ret)
|
||||
detail::invoke(e);
|
||||
return ret;
|
||||
@ -863,150 +857,152 @@ public:
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &> map(F &&f) & {
|
||||
if (has_value())
|
||||
return detail::invoke(std::forward<F>(f), value());
|
||||
return nullopt;
|
||||
detail::get_map_return<F, T &> map(F &&f) & {
|
||||
using result = detail::get_map_return<F, T&>;
|
||||
return has_value() ?
|
||||
detail::invoke(std::forward<F>(f), **this) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &> map(F &&f) & {
|
||||
detail::get_map_return<F, T &> map(F &&f) & {
|
||||
if (!has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f), value());
|
||||
return {};
|
||||
detail::invoke(std::forward<F>(f), **this);
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &> map(F &&f) & {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
return detail::invoke(std::forward<F>(f).value(), value());
|
||||
detail::get_map_return<F, T &> map(F &&f) & {
|
||||
using result = detail::get_map_return<F, T&>;
|
||||
return (f.has_value() && has_value()) ?
|
||||
detail::invoke(*std::forward<F>(f), **this) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &> map(F &&f) & {
|
||||
detail::get_map_return<F, T &> map(F &&f) & {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f).value(), value());
|
||||
return {};
|
||||
detail::invoke(*std::forward<F>(f), **this);
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
if (has_value())
|
||||
return detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return {};
|
||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
using result = detail::get_map_return<F, T&&>;
|
||||
return has_value() ?
|
||||
detail::invoke(std::forward<F>(f), std::move(**this)) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
if (!has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return {};
|
||||
detail::invoke(std::forward<F>(f), std::move(**this));
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
return detail::invoke(std::forward<F>(f).value(), std::move(value()));
|
||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
using result = detail::get_map_return<F, T&&>;
|
||||
return (f.has_value() && has_value()) ?
|
||||
detail::invoke(*std::forward<F>(f), std::move(**this)) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
detail::get_map_return<F, T &&> map(F &&f) && {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f).value(), std::move(value()));
|
||||
return {};
|
||||
detail::invoke(*std::forward<F>(f), std::move(**this));
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T const &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
if (has_value())
|
||||
return detail::invoke(std::forward<F>(f), value());
|
||||
return nullopt;
|
||||
using result = detail::get_map_return<F, T const &>;
|
||||
return this->has_value() ? result(detail::invoke(std::forward<F>(f), **this)) : result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T const &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
if (!has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f), value());
|
||||
return {};
|
||||
detail::invoke(std::forward<F>(f), **this);
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T const &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
return detail::invoke(std::forward<F>(f).value(), value());
|
||||
using result = detail::get_map_return<F, const T&>;
|
||||
return (f.has_value() && has_value()) ?
|
||||
detail::invoke(*std::forward<F>(f), **this) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T const &> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
detail::get_map_return<F, T const &> map(F &&f) const & {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f).value(), value());
|
||||
return {};
|
||||
detail::invoke(*std::forward<F>(f), **this);
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T const &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &&> map(F &&f) const && {
|
||||
if (has_value())
|
||||
return detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return nullopt;
|
||||
using result = detail::get_map_return<F, const T&&>;
|
||||
return has_value() ?
|
||||
detail::invoke(std::forward<F>(f), std::move(**this)) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::disable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T const &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &&> map(F &&f) const && {
|
||||
detail::get_map_return<F, T const &&> map(F &&f) const && {
|
||||
if (!has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f), std::move(value()));
|
||||
return {};
|
||||
detail::invoke(std::forward<F>(f), std::move(**this));
|
||||
return monostate{};
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::disable_if_ret_void<F, T const &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T const &&> map(F &&f) const && {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
return detail::invoke(std::forward<F>(f).value(), std::move(value()));
|
||||
using result = detail::get_map_return<F, const T&&>;
|
||||
return (f.has_value() && has_value()) ?
|
||||
detail::invoke(*std::forward<F>(f), std::move(**this)) :
|
||||
result(nullopt);
|
||||
}
|
||||
|
||||
template <class F, detail::enable_if_optional<F> * = nullptr,
|
||||
detail::enable_if_ret_void<F, T const &&> * = nullptr>
|
||||
constexpr detail::get_map_return<F, T &> map(F &&f) const && {
|
||||
detail::get_map_return<F, T &> map(F &&f) const && {
|
||||
if (!f.has_value() || !has_value())
|
||||
return nullopt;
|
||||
|
||||
detail::invoke(std::forward<F>(f).value(), std::move(value()));
|
||||
return {};
|
||||
detail::invoke(*std::forward<F>(f), std::move(**this));
|
||||
return monostate{};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,10 @@
|
||||
constexpr bool TOKENPASTE2(rqure, __LINE__) = e; \
|
||||
REQUIRE(e);
|
||||
|
||||
constexpr int get_int(int) { return 42; }
|
||||
constexpr tl::optional<int> get_opt_int(int) { return 42; }
|
||||
|
||||
|
||||
// What is Clang Format up to?!
|
||||
TEST_CASE("Monadic operations",
|
||||
"[monadic]"){SECTION("map"){// lhs is empty
|
||||
@ -22,7 +26,7 @@ STATIC_REQUIRE((std::is_same<decltype(o2r), tl::optional<int>>::value));
|
||||
REQUIRE(o2r.value() == 42);
|
||||
|
||||
struct rval_call_map {
|
||||
auto operator()(int) && { return 42.0; };
|
||||
double operator()(int) && { return 42.0; };
|
||||
};
|
||||
|
||||
// ensure that function object is forwarded
|
||||
@ -56,8 +60,174 @@ auto f7 = tl::make_optional([](const int &i) { return; });
|
||||
auto o7r = o7.map(f7);
|
||||
STATIC_REQUIRE((std::is_same<decltype(o7r), tl::optional<tl::monostate>>::value));
|
||||
REQUIRE(o6r.has_value());
|
||||
|
||||
// test each overload in turn
|
||||
tl::optional<int> o8 = 42;
|
||||
auto o8r = o8.map([](int){return 42;});
|
||||
REQUIRE(*o8r == 42);
|
||||
|
||||
tl::optional<int> o9 = 42;
|
||||
auto o9r = o9.map([](int){return;});
|
||||
REQUIRE(o9r);
|
||||
|
||||
tl::optional<int> o10 = 42;
|
||||
auto o10r = o10.map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(*o10r == 42);
|
||||
|
||||
tl::optional<int> o11 = 42;
|
||||
auto o11r = o11.map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(o11r);
|
||||
|
||||
tl::optional<int> o12 = 42;
|
||||
auto o12r = std::move(o12).map([](int){return 42;});
|
||||
REQUIRE(*o12r == 42);
|
||||
|
||||
tl::optional<int> o13 = 42;
|
||||
auto o13r = std::move(o13).map([](int){return;});
|
||||
REQUIRE(o13r);
|
||||
|
||||
tl::optional<int> o14 = 42;
|
||||
auto o14r = std::move(o14).map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(*o14r == 42);
|
||||
|
||||
tl::optional<int> o15 = 42;
|
||||
auto o15r = std::move(o15).map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(o15r);
|
||||
|
||||
const tl::optional<int> o16 = 42;
|
||||
auto o16r = o16.map([](int){return 42;});
|
||||
REQUIRE(*o16r == 42);
|
||||
|
||||
const tl::optional<int> o17 = 42;
|
||||
auto o17r = o17.map([](int){return;});
|
||||
REQUIRE(o17r);
|
||||
|
||||
const tl::optional<int> o18 = 42;
|
||||
auto o18r = o18.map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(*o18r == 42);
|
||||
|
||||
const tl::optional<int> o19 = 42;
|
||||
auto o19r = o19.map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(o19r);
|
||||
|
||||
const tl::optional<int> o20 = 42;
|
||||
auto o20r = std::move(o20).map([](int){return 42;});
|
||||
REQUIRE(*o20r == 42);
|
||||
|
||||
const tl::optional<int> o21 = 42;
|
||||
auto o21r = std::move(o21).map([](int){return;});
|
||||
REQUIRE(o21r);
|
||||
|
||||
const tl::optional<int> o22 = 42;
|
||||
auto o22r = std::move(o22).map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(*o22r == 42);
|
||||
|
||||
const tl::optional<int> o23 = 42;
|
||||
auto o23r = std::move(o23).map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(o23r);
|
||||
|
||||
tl::optional<int> o24 = tl::nullopt;
|
||||
auto o24r = o24.map([](int){return 42;});
|
||||
REQUIRE(!o24r);
|
||||
|
||||
tl::optional<int> o25 = tl::nullopt;
|
||||
auto o25r = o25.map([](int){return;});
|
||||
REQUIRE(!o25r);
|
||||
|
||||
tl::optional<int> o26 = tl::nullopt;
|
||||
auto o26r = o26.map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(!o26r);
|
||||
|
||||
tl::optional<int> o27 = tl::nullopt;
|
||||
auto o27r = o27.map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(!o27r);
|
||||
|
||||
tl::optional<int> o28 = tl::nullopt;
|
||||
auto o28r = std::move(o28).map([](int){return 42;});
|
||||
REQUIRE(!o28r);
|
||||
|
||||
tl::optional<int> o29 = tl::nullopt;
|
||||
auto o29r = std::move(o29).map([](int){return;});
|
||||
REQUIRE(!o29r);
|
||||
|
||||
tl::optional<int> o30 = tl::nullopt;
|
||||
auto o30r = std::move(o30).map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(!o30r);
|
||||
|
||||
tl::optional<int> o31 = tl::nullopt;
|
||||
auto o31r = std::move(o31).map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(!o31r);
|
||||
|
||||
const tl::optional<int> o32 = tl::nullopt;
|
||||
auto o32r = o32.map([](int){return 42;});
|
||||
REQUIRE(!o32r);
|
||||
|
||||
const tl::optional<int> o33 = tl::nullopt;
|
||||
auto o33r = o33.map([](int){return;});
|
||||
REQUIRE(!o33r);
|
||||
|
||||
const tl::optional<int> o34 = tl::nullopt;
|
||||
auto o34r = o34.map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(!o34r);
|
||||
|
||||
const tl::optional<int> o35 = tl::nullopt;
|
||||
auto o35r = o35.map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(!o35r);
|
||||
|
||||
const tl::optional<int> o36 = tl::nullopt;
|
||||
auto o36r = std::move(o36).map([](int){return 42;});
|
||||
REQUIRE(!o36r);
|
||||
|
||||
const tl::optional<int> o37 = tl::nullopt;
|
||||
auto o37r = std::move(o37).map([](int){return;});
|
||||
REQUIRE(!o37r);
|
||||
|
||||
const tl::optional<int> o38 = tl::nullopt;
|
||||
auto o38r = std::move(o38).map(tl::make_optional([](int){return 42;}));
|
||||
REQUIRE(!o38r);
|
||||
|
||||
const tl::optional<int> o39 = tl::nullopt;
|
||||
auto o39r = std::move(o39).map(tl::make_optional([](int){return;}));
|
||||
REQUIRE(!o39r);
|
||||
}
|
||||
|
||||
|
||||
SECTION("map constexpr") {
|
||||
// test each overload in turn
|
||||
constexpr tl::optional<int> o16 = 42;
|
||||
constexpr auto o16r = o16.map(get_int);
|
||||
STATIC_REQUIRE(*o16r == 42);
|
||||
|
||||
constexpr tl::optional<int> 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<int> o20 = 42;
|
||||
constexpr auto o20r = std::move(o20).map(get_int);
|
||||
STATIC_REQUIRE(*o20r == 42);
|
||||
|
||||
constexpr tl::optional<int> o22 = 42;
|
||||
constexpr auto o22r = std::move(o22).map(opt_int);
|
||||
STATIC_REQUIRE(*o22r == 42);
|
||||
|
||||
constexpr tl::optional<int> o32 = tl::nullopt;
|
||||
constexpr auto o32r = o32.map(get_int);
|
||||
STATIC_REQUIRE(!o32r);
|
||||
|
||||
constexpr tl::optional<int> o34 = tl::nullopt;
|
||||
constexpr auto o34r = o34.map(opt_int);
|
||||
STATIC_REQUIRE(!o34r);
|
||||
|
||||
constexpr tl::optional<int> o36 = tl::nullopt;
|
||||
constexpr auto o36r = std::move(o36).map(get_int);
|
||||
STATIC_REQUIRE(!o36r);
|
||||
|
||||
constexpr tl::optional<int> o38 = tl::nullopt;
|
||||
constexpr auto o38r = std::move(o38).map(opt_int);
|
||||
STATIC_REQUIRE(!o38r);
|
||||
}
|
||||
|
||||
SECTION("bind") {
|
||||
|
||||
// lhs is empty
|
||||
@ -85,7 +255,7 @@ SECTION("bind") {
|
||||
REQUIRE(!o4r);
|
||||
|
||||
struct rval_call_bind {
|
||||
auto operator()(int) && { return tl::optional<double>(42.0); };
|
||||
tl::optional<double> operator()(int) && { return tl::optional<double>(42.0); };
|
||||
};
|
||||
|
||||
// ensure that function object is forwarded
|
||||
@ -106,6 +276,122 @@ SECTION("bind") {
|
||||
auto o7r = o7.bind([](const int &i) { return tl::optional<double>(i); });
|
||||
STATIC_REQUIRE((std::is_same<decltype(o7r), tl::optional<double>>::value));
|
||||
REQUIRE(o7r.value() == 42);
|
||||
|
||||
// test each overload in turn
|
||||
tl::optional<int> o8 = 42;
|
||||
auto o8r = o8.bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(*o8r == 42);
|
||||
|
||||
tl::optional<int> o9 = 42;
|
||||
auto o9r = std::move(o9).bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(*o9r == 42);
|
||||
|
||||
const tl::optional<int> o10 = 42;
|
||||
auto o10r = o10.bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(*o10r == 42);
|
||||
|
||||
const tl::optional<int> o11 = 42;
|
||||
auto o11r = std::move(o11).bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(*o11r == 42);
|
||||
|
||||
tl::optional<int> o12 = 42;
|
||||
auto o12r = o12.bind([](int i) { return tl::make_optional(42); }, []{return;});
|
||||
REQUIRE(*o12r == 42);
|
||||
|
||||
tl::optional<int> o13 = 42;
|
||||
auto o13r = std::move(o13).bind([](int i) { return tl::make_optional(42); }, []{return;});
|
||||
REQUIRE(*o13r == 42);
|
||||
|
||||
const tl::optional<int> o14 = 42;
|
||||
auto o14r = o14.bind([](int i) { return tl::make_optional(42); }, []{return;});
|
||||
REQUIRE(*o14r == 42);
|
||||
|
||||
const tl::optional<int> o15 = 42;
|
||||
auto o15r = std::move(o15).bind([](int i) { return tl::make_optional(42); }, []{return;});
|
||||
REQUIRE(*o15r == 42);
|
||||
|
||||
tl::optional<int> o16 = tl::nullopt;
|
||||
auto o16r = o16.bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(!o16r);
|
||||
|
||||
tl::optional<int> o17 = tl::nullopt;
|
||||
auto o17r = std::move(o17).bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(!o17r);
|
||||
|
||||
const tl::optional<int> o18 = tl::nullopt;
|
||||
auto o18r = o18.bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(!o18r);
|
||||
|
||||
const tl::optional<int> o19 = tl::nullopt;
|
||||
auto o19r = std::move(o19).bind([](int i) { return tl::make_optional(42); });
|
||||
REQUIRE(!o19r);
|
||||
|
||||
tl::optional<int> o20 = tl::nullopt;
|
||||
bool c20 = false;
|
||||
auto o20r = o20.bind([](int i) { return tl::make_optional(42); }, [&]{c20 = true;});
|
||||
REQUIRE(!o20r);
|
||||
REQUIRE(!c20);
|
||||
|
||||
tl::optional<int> o21 = tl::nullopt;
|
||||
bool c21 = false;
|
||||
auto o21r = std::move(o21).bind([](int i) { return tl::make_optional(42); }, [&]{c21 = true;});
|
||||
REQUIRE(!o21r);
|
||||
REQUIRE(!c21);
|
||||
|
||||
const tl::optional<int> o22 = tl::nullopt;
|
||||
bool c22 = false;
|
||||
auto o22r = o22.bind([](int i) { return tl::make_optional(42); }, [&]{c22 = true;});
|
||||
REQUIRE(!o22r);
|
||||
REQUIRE(!c22);
|
||||
|
||||
const tl::optional<int> o23 = tl::nullopt;
|
||||
bool c23 = false;
|
||||
auto o23r = std::move(o23).bind([](int i) { return tl::make_optional(42); }, [&]{c23 = true;});
|
||||
REQUIRE(!o23r);
|
||||
REQUIRE(!c23);
|
||||
|
||||
tl::optional<int> o24 = 42;
|
||||
bool c24 = false;
|
||||
auto o24r = o24.bind([](int i) { return tl::optional<int>{tl::nullopt}; }, [&]{c24 = true;});
|
||||
REQUIRE(!o24r);
|
||||
REQUIRE(c24);
|
||||
|
||||
tl::optional<int> o25 = 42;
|
||||
bool c25 = false;
|
||||
auto o25r = std::move(o25).bind([](int i) { return tl::optional<int>{tl::nullopt}; }, [&]{c25 = true;});
|
||||
REQUIRE(!o25r);
|
||||
REQUIRE(c25);
|
||||
|
||||
const tl::optional<int> o26 = 42;
|
||||
bool c26 = false;
|
||||
auto o26r = o26.bind([](int i) { return tl::optional<int>{tl::nullopt};}, [&]{c26 = true;});
|
||||
REQUIRE(!o26r);
|
||||
REQUIRE(c26);
|
||||
|
||||
const tl::optional<int> o27 = 42;
|
||||
bool c27 = false;
|
||||
auto o27r = std::move(o27).bind([](int i) { return tl::optional<int>{tl::nullopt};}, [&]{c27 = true;});
|
||||
REQUIRE(!o27r);
|
||||
REQUIRE(c27);
|
||||
|
||||
}
|
||||
|
||||
SECTION("constexpr bind") {
|
||||
constexpr tl::optional<int> o10 = 42;
|
||||
constexpr auto o10r = o10.bind(get_opt_int);
|
||||
REQUIRE(*o10r == 42);
|
||||
|
||||
constexpr tl::optional<int> o11 = 42;
|
||||
constexpr auto o11r = std::move(o11).bind(get_opt_int);
|
||||
REQUIRE(*o11r == 42);
|
||||
|
||||
constexpr tl::optional<int> o18 = tl::nullopt;
|
||||
constexpr auto o18r = o18.bind(get_opt_int);
|
||||
REQUIRE(!o18r);
|
||||
|
||||
constexpr tl::optional<int> o19 = tl::nullopt;
|
||||
constexpr auto o19r = std::move(o19).bind(get_opt_int);
|
||||
REQUIRE(!o19r);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
Reference in New Issue
Block a user