mirror of
https://github.com/TartanLlama/optional.git
synced 2025-08-04 20:24:26 +02:00
Add static asserts
This commit is contained in:
@@ -283,12 +283,10 @@ TEST_CASE("Monadic operations", "[monadic]") {
|
|||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
REQUIRE(*o1.conjunction(42.0) == 42.0);
|
REQUIRE(*o1.conjunction(42.0) == 42.0);
|
||||||
REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
|
REQUIRE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
|
||||||
REQUIRE(!o1.conjunction(tl::nullopt));
|
|
||||||
|
|
||||||
tl::optional<int> o2;
|
tl::optional<int> o2;
|
||||||
REQUIRE(!o2.conjunction(42.0));
|
REQUIRE(!o2.conjunction(42.0));
|
||||||
REQUIRE(!o2.conjunction(std::string{"hello"}));
|
REQUIRE(!o2.conjunction(std::string{"hello"}));
|
||||||
REQUIRE(!o2.conjunction(tl::nullopt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("map_or") {
|
SECTION("map_or") {
|
||||||
|
@@ -176,8 +176,8 @@ template <class T, class... U>
|
|||||||
using disable_if_ret_void = enable_if_t<!returns_void<T &&, U...>::value>;
|
using disable_if_ret_void = enable_if_t<!returns_void<T &&, U...>::value>;
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
using enable_forward_value =
|
using enable_forward_value = detail::enable_if_t<
|
||||||
detail::enable_if_t<std::is_constructible<T, U &&>::value &&
|
std::is_constructible<T, U &&>::value &&
|
||||||
!std::is_same<detail::decay_t<U>, in_place_t>::value &&
|
!std::is_same<detail::decay_t<U>, in_place_t>::value &&
|
||||||
!std::is_same<optional<T>, detail::decay_t<U>>::value>;
|
!std::is_same<optional<T>, detail::decay_t<U>>::value>;
|
||||||
|
|
||||||
@@ -221,7 +221,8 @@ using enable_assign_from_other = detail::enable_if_t<
|
|||||||
// TODO make a version which works with MSVC
|
// TODO make a version which works with MSVC
|
||||||
template <class T, class U = T> struct is_swappable : std::true_type {};
|
template <class T, class U = T> struct is_swappable : std::true_type {};
|
||||||
|
|
||||||
template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
|
template <class T, class U = T>
|
||||||
|
struct is_nothrow_swappable : std::true_type {};
|
||||||
#else
|
#else
|
||||||
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
||||||
namespace swap_adl_tests {
|
namespace swap_adl_tests {
|
||||||
@@ -249,7 +250,8 @@ template <class T>
|
|||||||
struct is_std_swap_noexcept
|
struct is_std_swap_noexcept
|
||||||
: std::integral_constant<bool,
|
: std::integral_constant<bool,
|
||||||
std::is_nothrow_move_constructible<T>::value &&
|
std::is_nothrow_move_constructible<T>::value &&
|
||||||
std::is_nothrow_move_assignable<T>::value> {};
|
std::is_nothrow_move_assignable<T>::value> {
|
||||||
|
};
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
||||||
@@ -282,12 +284,11 @@ struct is_nothrow_swappable
|
|||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
is_swappable<T, U>::value &&
|
is_swappable<T, U>::value &&
|
||||||
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
||||||
&&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
||||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
||||||
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
&&detail::swap_adl_tests::is_adl_swap_noexcept<
|
||||||
U>::value))> {
|
T, U>::value))> {};
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The storage base manages the actual storage, and correctly propagates
|
// The storage base manages the actual storage, and correctly propagates
|
||||||
@@ -340,7 +341,8 @@ template <class T> struct optional_storage_base<T, true> {
|
|||||||
|
|
||||||
// This base class provides some handy member functions which can be used in
|
// This base class provides some handy member functions which can be used in
|
||||||
// further derived classes
|
// further derived classes
|
||||||
template <class T> struct optional_operations_base : optional_storage_base<T> {
|
template <class T>
|
||||||
|
struct optional_operations_base : optional_storage_base<T> {
|
||||||
using optional_storage_base<T>::optional_storage_base;
|
using optional_storage_base<T>::optional_storage_base;
|
||||||
|
|
||||||
void hard_reset() noexcept {
|
void hard_reset() noexcept {
|
||||||
@@ -417,7 +419,8 @@ struct optional_move_base : optional_copy_base<T> {
|
|||||||
#else
|
#else
|
||||||
template <class T, bool = false> struct optional_move_base;
|
template <class T, bool = false> struct optional_move_base;
|
||||||
#endif
|
#endif
|
||||||
template <class T> struct optional_move_base<T, false> : optional_copy_base<T> {
|
template <class T>
|
||||||
|
struct optional_move_base<T, false> : optional_copy_base<T> {
|
||||||
using optional_copy_base<T>::optional_copy_base;
|
using optional_copy_base<T>::optional_copy_base;
|
||||||
|
|
||||||
optional_move_base() = default;
|
optional_move_base() = default;
|
||||||
@@ -494,7 +497,6 @@ struct optional_move_assign_base<T, false> : optional_copy_assign_base<T> {
|
|||||||
this->assign(std::move(rhs));
|
this->assign(std::move(rhs));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// optional_delete_ctor_base will conditionally delete copy and move
|
// optional_delete_ctor_base will conditionally delete copy and move
|
||||||
@@ -629,6 +631,14 @@ class optional : private detail::optional_move_assign_base<T>,
|
|||||||
private detail::optional_delete_assign_base<T> {
|
private detail::optional_delete_assign_base<T> {
|
||||||
using base = detail::optional_move_assign_base<T>;
|
using base = detail::optional_move_assign_base<T>;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
!std::is_reference<T>::value,
|
||||||
|
"instantiation of optional with a reference type is ill-formed");
|
||||||
|
static_assert(!std::is_same<T, in_place_t>::value,
|
||||||
|
"instantiation of optional with in_place_t is ill-formed");
|
||||||
|
static_assert(!std::is_same<detail::decay_t<T>, nullopt_t>::value,
|
||||||
|
"instantiation of optional with nullopt_t is ill-formed");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// The different versions for C++14 and 11 are needed because deduced return
|
// The different versions for C++14 and 11 are needed because deduced return
|
||||||
// types are not SFINAE-safe. This provides better support for things like
|
// types are not SFINAE-safe. This provides better support for things like
|
||||||
@@ -691,11 +701,10 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// Carries out some operation which returns an optional on the stored object
|
/// Carries out some operation which returns an optional on the stored
|
||||||
/// if there is one.
|
/// object if there is one. \requires `std::invoke(std::forward<F>(f),
|
||||||
/// \requires `std::invoke(std::forward<F>(f), value())`
|
/// value())` returns a `std::optional<U>` for some `U`. \returns Let `U` be
|
||||||
/// returns a `std::optional<U>` for some `U`. \returns Let `U` be the result
|
/// the result of `std::invoke(std::forward<F>(f), value())`. Returns a
|
||||||
/// of `std::invoke(std::forward<F>(f), value())`. Returns a
|
|
||||||
/// `std::optional<U>`. The return value is empty if `*this` is empty,
|
/// `std::optional<U>`. The return value is empty if `*this` is empty,
|
||||||
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
|
||||||
/// is returned.
|
/// is returned.
|
||||||
@@ -714,7 +723,8 @@ public:
|
|||||||
/// \group and_then
|
/// \group and_then
|
||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&> and_then(F &&f) && {
|
TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t<F, T &&>
|
||||||
|
and_then(F &&f) && {
|
||||||
using result = detail::invoke_result_t<F, T &&>;
|
using result = detail::invoke_result_t<F, T &&>;
|
||||||
static_assert(detail::is_optional<result>::value,
|
static_assert(detail::is_optional<result>::value,
|
||||||
"F must return an optional");
|
"F must return an optional");
|
||||||
@@ -1090,7 +1100,8 @@ public:
|
|||||||
/// optional(in_place_t, Args&&... args);
|
/// optional(in_place_t, Args&&... args);
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
constexpr explicit optional(
|
constexpr explicit optional(
|
||||||
detail::enable_if_t<std::is_constructible<T, Args...>::value, in_place_t>,
|
detail::enable_if_t<std::is_constructible<T, Args...>::value,
|
||||||
|
in_place_t>,
|
||||||
Args &&... args)
|
Args &&... args)
|
||||||
: base(in_place, std::forward<Args>(args)...) {}
|
: base(in_place, std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
@@ -1123,9 +1134,9 @@ public:
|
|||||||
|
|
||||||
/// Converting copy constructor.
|
/// Converting copy constructor.
|
||||||
/// \synopsis template <class U> optional(const optional<U> &rhs);
|
/// \synopsis template <class U> optional(const optional<U> &rhs);
|
||||||
template <
|
template <class U, detail::enable_from_other<T, U, const U &> * = nullptr,
|
||||||
class U, detail::enable_from_other<T, U, const U &> * = nullptr,
|
detail::enable_if_t<std::is_convertible<const U &, T>::value> * =
|
||||||
detail::enable_if_t<std::is_convertible<const U &, T>::value> * = nullptr>
|
nullptr>
|
||||||
optional(const optional<U> &rhs) {
|
optional(const optional<U> &rhs) {
|
||||||
this->construct(*rhs);
|
this->construct(*rhs);
|
||||||
}
|
}
|
||||||
@@ -1318,7 +1329,9 @@ public:
|
|||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \exclude
|
/// \exclude
|
||||||
constexpr const T &&operator*() const && { return std::move(this->m_value); }
|
constexpr const T &&operator*() const && {
|
||||||
|
return std::move(this->m_value);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \returns whether or not the optional has a value
|
/// \returns whether or not the optional has a value
|
||||||
@@ -1563,7 +1576,8 @@ inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
|
|||||||
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
|
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
|
||||||
/// &rhs);
|
/// &rhs);
|
||||||
template <class T,
|
template <class T,
|
||||||
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
|
detail::enable_if_t<std::is_move_constructible<T>::value> * =
|
||||||
|
nullptr,
|
||||||
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
|
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
|
||||||
void swap(optional<T> & lhs,
|
void swap(optional<T> & lhs,
|
||||||
optional<T> & rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
optional<T> & rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
||||||
|
Reference in New Issue
Block a user