From 7ef0154330ff26710dd83c9f100df91061edbb5a Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Tue, 19 Feb 2019 10:57:43 +0000 Subject: [PATCH 1/3] Use correct is_swappable implementation for VS2017+ --- tests/noexcept.cpp | 4 ++-- tl/optional.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/noexcept.cpp b/tests/noexcept.cpp index edfa88f..967f39e 100644 --- a/tests/noexcept.cpp +++ b/tests/noexcept.cpp @@ -22,7 +22,7 @@ TEST_CASE("Noexcept", "[noexcept]") { SECTION("swap") { //TODO see why this fails -#if !defined(_MSC_VER) || _MSC_VER > 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 REQUIRE(noexcept(swap(o1, o2)) == noexcept(o1.swap(o2))); struct nothrow_swappable { @@ -48,7 +48,7 @@ TEST_CASE("Noexcept", "[noexcept]") { SECTION("constructors") { //TODO see why this fails -#if !defined(_MSC_VER) || _MSC_VER > 1900 +#if !defined(_MSC_VER) || _MSC_VER >= 1900 REQUIRE(noexcept(tl::optional{})); REQUIRE(noexcept(tl::optional{tl::nullopt})); diff --git a/tl/optional.hpp b/tl/optional.hpp index c63d820..a8b2590 100644 --- a/tl/optional.hpp +++ b/tl/optional.hpp @@ -278,8 +278,8 @@ using enable_assign_from_other = detail::enable_if_t< !std::is_assignable &>::value && !std::is_assignable &&>::value>; -#ifdef _MSC_VER -// TODO make a version which works with MSVC +#if defined(_MSC_VER) && _MSC_VER < 1900 +// TODO make a version which works with MSVC 2015 template struct is_swappable : std::true_type {}; template struct is_nothrow_swappable : std::true_type {}; From d2c6fa68c764f2ea7d1867b4049ee642ea0ea29b Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Tue, 19 Feb 2019 14:58:09 +0000 Subject: [PATCH 2/3] Move is_swappable implementation, correct MSC_VER check --- tl/optional.hpp | 146 ++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/tl/optional.hpp b/tl/optional.hpp index a8b2590..28691bf 100644 --- a/tl/optional.hpp +++ b/tl/optional.hpp @@ -204,6 +204,79 @@ using invoke_result = invoke_result_impl; template using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template struct is_swappable : std::true_type {}; + +template struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template tag swap(T &, T &); +template tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype( + detail::swap_adl_tests::uses_std(0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value + &&detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> { +}; +#endif #endif // std::void_t from C++17 @@ -278,79 +351,6 @@ using enable_assign_from_other = detail::enable_if_t< !std::is_assignable &>::value && !std::is_assignable &&>::value>; -#if defined(_MSC_VER) && _MSC_VER < 1900 -// TODO make a version which works with MSVC 2015 -template struct is_swappable : std::true_type {}; - -template struct is_nothrow_swappable : std::true_type {}; -#else -// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept -namespace swap_adl_tests { -// if swap ADL finds this then it would call std::swap otherwise (same -// signature) -struct tag {}; - -template tag swap(T &, T &); -template tag swap(T (&a)[N], T (&b)[N]); - -// helper functions to test if an unqualified swap is possible, and if it -// becomes std::swap -template std::false_type can_swap(...) noexcept(false); -template (), std::declval()))> -std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), - std::declval()))); - -template std::false_type uses_std(...); -template -std::is_same(), std::declval())), tag> -uses_std(int); - -template -struct is_std_swap_noexcept - : std::integral_constant::value && - std::is_nothrow_move_assignable::value> {}; - -template -struct is_std_swap_noexcept : is_std_swap_noexcept {}; - -template -struct is_adl_swap_noexcept - : std::integral_constant(0))> {}; -} // namespace swap_adl_tests - -template -struct is_swappable - : std::integral_constant< - bool, - decltype(detail::swap_adl_tests::can_swap(0))::value && - (!decltype(detail::swap_adl_tests::uses_std(0))::value || - (std::is_move_assignable::value && - std::is_move_constructible::value))> {}; - -template -struct is_swappable - : std::integral_constant< - bool, - decltype(detail::swap_adl_tests::can_swap(0))::value && - (!decltype( - detail::swap_adl_tests::uses_std(0))::value || - is_swappable::value)> {}; - -template -struct is_nothrow_swappable - : std::integral_constant< - bool, - is_swappable::value && - ((decltype(detail::swap_adl_tests::uses_std(0))::value - &&detail::swap_adl_tests::is_std_swap_noexcept::value) || - (!decltype(detail::swap_adl_tests::uses_std(0))::value && - detail::swap_adl_tests::is_adl_swap_noexcept::value))> { -}; -#endif - // The storage base manages the actual storage, and correctly propagates // trivial destruction from T. This case is for when T is not trivially // destructible. From 9399c3033046753b804cd56a76a9438646a3f63d Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Tue, 19 Feb 2019 14:58:36 +0000 Subject: [PATCH 3/3] Correct MSC_VER check --- tests/noexcept.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/noexcept.cpp b/tests/noexcept.cpp index 967f39e..b12fdea 100644 --- a/tests/noexcept.cpp +++ b/tests/noexcept.cpp @@ -22,7 +22,7 @@ TEST_CASE("Noexcept", "[noexcept]") { SECTION("swap") { //TODO see why this fails -#if !defined(_MSC_VER) || _MSC_VER >= 1900 +#if !defined(_MSC_VER) || _MSC_VER > 1900 REQUIRE(noexcept(swap(o1, o2)) == noexcept(o1.swap(o2))); struct nothrow_swappable {