From 7ca0facc75d35716284ca675c88d922313e90f98 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 2 Oct 2017 08:57:21 +0100 Subject: [PATCH] Better is_swappable impl --- optional.hpp | 66 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/optional.hpp b/optional.hpp index 4a8230b..1088e0f 100644 --- a/optional.hpp +++ b/optional.hpp @@ -108,21 +108,63 @@ namespace tl { !std::is_assignable&&>::value >; - //TODO improve - template - struct is_swappable : std::false_type{}; - template - struct is_swappable(), std::declval()))>> - : std::true_type{}; + // 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 {}; - //TODO improve - template - struct is_nothrow_swappable : std::false_type{}; + template tag swap(T&, T&); + template tag swap(T (&a)[N], T (&b)[N]); - template - struct is_nothrow_swappable(), std::declval()))>> - : std::true_type{}; + // 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))> { }; + } + + template + struct is_swappable : std::integral_constant(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(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + is_swappable::value) + > {}; + + template + struct is_nothrow_swappable : std::integral_constant::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) + ) + > {}; } // [optional.nullopt], no-value state indicator