diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp index 31b130a..a25e71e 100644 --- a/include/tl/expected.hpp +++ b/include/tl/expected.hpp @@ -951,7 +951,8 @@ struct expected_move_base : expected_copy_base { expected_move_base(const expected_move_base &rhs) = default; expected_move_base(expected_move_base &&rhs) noexcept( - std::is_nothrow_move_constructible::value) + is_void_or>::value + &&std::is_nothrow_move_constructible::value) : expected_copy_base(no_init) { if (rhs.has_value()) { this->construct_with(std::move(rhs)); @@ -1028,8 +1029,10 @@ struct expected_move_assign_base expected_move_assign_base & operator=(expected_move_assign_base &&rhs) noexcept( - std::is_nothrow_move_constructible::value - &&std::is_nothrow_move_assignable::value) { + is_void_or, + std::is_nothrow_move_assignable>>::value + &&std::is_nothrow_move_constructible::value + &&std::is_nothrow_move_assignable::value) { this->assign(std::move(rhs)); return *this; } @@ -1220,8 +1223,9 @@ class expected : private detail::expected_move_assign_base, "T must not be in_place_t"); static_assert(!std::is_same::type>::value, "T must not be unexpect_t"); - static_assert(!std::is_same>::type>::value, - "T must not be unexpected"); + static_assert( + !std::is_same>::type>::value, + "T must not be unexpected"); static_assert(!std::is_reference::value, "E must not be a reference"); T *valptr() { return std::addressof(this->m_val); } diff --git a/tests/constructors.cpp b/tests/constructors.cpp index df168ba..0457cbc 100644 --- a/tests/constructors.cpp +++ b/tests/constructors.cpp @@ -13,6 +13,15 @@ struct takes_init_and_variadic { : v(l), t(std::forward(args)...) {} }; +struct canthrow_move { + canthrow_move() = default; + canthrow_move(const canthrow_move &) = default; + canthrow_move & operator=(const canthrow_move &) = default; + + canthrow_move(canthrow_move &&) noexcept(false) {} + canthrow_move & operator=(canthrow_move &&) = default; +}; + TEST_CASE("Constructors", "[constructors]") { { tl::expected e; @@ -73,6 +82,8 @@ TEST_CASE("Constructors", "[constructors]") { # if !defined(TL_EXPECTED_GCC49) REQUIRE(std::is_trivially_move_constructible::value); REQUIRE(std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); # endif } @@ -88,6 +99,8 @@ TEST_CASE("Constructors", "[constructors]") { # if !defined(TL_EXPECTED_GCC49) REQUIRE(!std::is_trivially_move_constructible::value); REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); # endif } @@ -103,6 +116,8 @@ TEST_CASE("Constructors", "[constructors]") { # if !defined(TL_EXPECTED_GCC49) REQUIRE(!std::is_trivially_move_constructible::value); REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); # endif } @@ -118,6 +133,59 @@ TEST_CASE("Constructors", "[constructors]") { # if !defined(TL_EXPECTED_GCC49) REQUIRE(!std::is_trivially_move_constructible::value); REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); +# endif + } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(!std::is_trivially_move_constructible::value); + REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(!std::is_nothrow_move_constructible::value); + REQUIRE(!std::is_nothrow_move_assignable::value); +# endif + } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(!std::is_trivially_move_constructible::value); + REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(!std::is_nothrow_move_constructible::value); + REQUIRE(!std::is_nothrow_move_assignable::value); +# endif + } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(!std::is_trivially_move_constructible::value); + REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(!std::is_nothrow_move_constructible::value); + REQUIRE(!std::is_nothrow_move_assignable::value); # endif } @@ -131,4 +199,55 @@ TEST_CASE("Constructors", "[constructors]") { REQUIRE(!e); REQUIRE(e.error() == 42); } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(std::is_trivially_move_constructible::value); + REQUIRE(std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); +# endif + } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(!std::is_trivially_move_constructible::value); + REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(std::is_nothrow_move_constructible::value); + REQUIRE(std::is_nothrow_move_assignable::value); +# endif + } + + { + tl::expected e; + REQUIRE(std::is_default_constructible::value); + REQUIRE(std::is_copy_constructible::value); + REQUIRE(std::is_move_constructible::value); + REQUIRE(std::is_copy_assignable::value); + REQUIRE(std::is_move_assignable::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value); + REQUIRE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value); +# if !defined(TL_EXPECTED_GCC49) + REQUIRE(!std::is_trivially_move_constructible::value); + REQUIRE(!std::is_trivially_move_assignable::value); + REQUIRE(!std::is_nothrow_move_constructible::value); + REQUIRE(!std::is_nothrow_move_assignable::value); +# endif + } }