From d82fcbbf31d11738ce930aba33fa9307ddf0128d Mon Sep 17 00:00:00 2001 From: X1aomu Date: Tue, 16 Apr 2024 14:33:17 +0800 Subject: [PATCH 1/3] fix: constraints of value_or() and error_or() --- include/zeus/expected.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zeus/expected.hpp b/include/zeus/expected.hpp index 150f5c0..98a57c2 100644 --- a/include/zeus/expected.hpp +++ b/include/zeus/expected.hpp @@ -1702,7 +1702,7 @@ class expected noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) #endif { - static_assert(std::is_copy_constructible_v, "T must be copy-constructible"); + static_assert(std::is_move_constructible_v, "T must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); if (this->m_has_val) { @@ -1737,7 +1737,7 @@ class expected noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) #endif { - static_assert(std::is_copy_constructible_v, "E must be copy-constructible"); + static_assert(std::is_move_constructible_v, "E must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); if (this->m_has_val) { @@ -2428,7 +2428,7 @@ class expected noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) #endif { - static_assert(std::is_copy_constructible_v, "E must be copy-constructible"); + static_assert(std::is_move_constructible_v, "E must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); if (this->m_has_val) { From 79c13d5ad27f2981f1ca2ed648b20d4e9a117291 Mon Sep 17 00:00:00 2001 From: X1aomu Date: Tue, 16 Apr 2024 15:28:56 +0800 Subject: [PATCH 2/3] test: noexcept on value_or() and error_or() --- tests/test_expected/CMakeLists.txt | 1 + tests/test_expected/noexcept_tests.cpp | 90 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tests/test_expected/noexcept_tests.cpp diff --git a/tests/test_expected/CMakeLists.txt b/tests/test_expected/CMakeLists.txt index c910bd6..160364d 100644 --- a/tests/test_expected/CMakeLists.txt +++ b/tests/test_expected/CMakeLists.txt @@ -3,6 +3,7 @@ project(test_expected) set(SOURCES base_tests.cpp monadic_tests.cpp + noexcept_tests.cpp test_expected_main.cpp ) diff --git a/tests/test_expected/noexcept_tests.cpp b/tests/test_expected/noexcept_tests.cpp new file mode 100644 index 0000000..7a404ee --- /dev/null +++ b/tests/test_expected/noexcept_tests.cpp @@ -0,0 +1,90 @@ +#include + +#include + +struct FromType +{ +}; + +enum class NoThrowConvertible +{ + Yes, + No, +}; + +template +struct ToType; + +template<> +struct ToType +{ + ToType() = default; + ToType(ToType const&) = default; + ToType(ToType&&) = default; + + ToType(FromType const&) noexcept {} +}; + +template<> +struct ToType +{ + ToType() = default; + ToType(ToType const&) = default; + ToType(ToType&&) = default; + + ToType(FromType const&) noexcept(false) {} +}; + +TEST_CASE("value_or() noexcept", "[noexcept, value_or]") +{ + { // noexcept(true) + using T = ToType; + using E = int; + using Expected = zeus::expected; + Expected e; + CHECK(noexcept(e.value_or(FromType {}))); + } + { // noexcept(false) + using T = ToType; + using E = int; + using Expected = zeus::expected; + Expected e; + CHECK_FALSE(noexcept(e.value_or(FromType {}))); + } +} + +TEST_CASE("error_or() noexcept", "[noexcept, error_or]") +{ + { // noexcept(true) + using T = int; + using E = ToType; + using Expected = zeus::expected; + Expected e; + CHECK(noexcept(e.error_or(FromType {}))); + } + { // noexcept(false) + using T = int; + using E = ToType; + using Expected = zeus::expected; + Expected e; + CHECK_FALSE(noexcept(e.error_or(FromType {}))); + } +} + +TEST_CASE("void-T error_or() noexcept", "[noexcept, error_or, void-T]") +{ + { // noexcept(true) + using T = void; + using E = ToType; + using Expected = zeus::expected; + Expected e; + CHECK(noexcept(e.error_or(FromType {}))); + } + { // noexcept(false) + using T = void; + using E = ToType; + using Expected = zeus::expected; + Expected e; + CHECK_FALSE(noexcept(e.error_or(FromType {}))); + } +} From 9e735608ecf66f801dc096dc55618ecdb1cfa227 Mon Sep 17 00:00:00 2001 From: X1aomu Date: Tue, 16 Apr 2024 14:32:42 +0800 Subject: [PATCH 3/3] fix: noexcept in C++17 --- include/zeus/expected.hpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/include/zeus/expected.hpp b/include/zeus/expected.hpp index 98a57c2..6a55a6a 100644 --- a/include/zeus/expected.hpp +++ b/include/zeus/expected.hpp @@ -114,6 +114,9 @@ inline constexpr bool is_copy_assignable_or_void_v = is_void_or_v inline constexpr bool is_move_assignable_or_void_v = is_void_or_v>; +template +inline constexpr bool is_nothrow_convertible_v = noexcept(static_cast(std::declval())); + } // namespace expected_detail template @@ -1681,9 +1684,7 @@ class expected template constexpr T value_or(U &&v) const & // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_copy_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_copy_constructible_v, "T must be copy-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); @@ -1698,9 +1699,7 @@ class expected } template constexpr T value_or(U &&v) && // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_move_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_move_constructible_v, "T must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); @@ -1716,9 +1715,7 @@ class expected template constexpr E error_or(G &&v) const & // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_copy_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_copy_constructible_v, "E must be copy-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); @@ -1733,9 +1730,7 @@ class expected } template constexpr E error_or(G &&v) && // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_move_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_move_constructible_v, "E must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); @@ -2407,9 +2402,7 @@ class expected template constexpr E error_or(G &&v) const & // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_copy_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_copy_constructible_v, "E must be copy-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true"); @@ -2424,9 +2417,7 @@ class expected } template constexpr E error_or(G &&v) && // -#if __cplusplus >= 202'002L // doesn't compile with C++17 with MSVC, may be a compiler bug - noexcept(std::is_nothrow_copy_constructible_v && std::is_nothrow_convertible_v) -#endif + noexcept(std::is_nothrow_move_constructible_v && expected_detail::is_nothrow_convertible_v) { static_assert(std::is_move_constructible_v, "E must be move-constructible"); static_assert(std::is_convertible_v, "is_convertible_v must be true");