diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp index 6e0fae8..dbf2830 100644 --- a/include/tl/expected.hpp +++ b/include/tl/expected.hpp @@ -235,24 +235,55 @@ template struct conjunction : std::true_type {}; template struct conjunction : B {}; template struct conjunction - : std::conditional, B>::type {}; + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; +template +struct is_pointer_to_non_const_member_func : std::true_type {}; + +template struct is_const_or_const_ref : std::false_type {}; +template struct is_const_or_const_ref : std::true_type {}; +template struct is_const_or_const_ref : std::true_type {}; +#endif // std::invoke from C++17 // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround template >{}>, - int = 0> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value + && is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, + int = 0> + constexpr auto invoke(Fn && f, Args && ... args) noexcept( noexcept(std::mem_fn(f)(std::forward(args)...))) - -> decltype(std::mem_fn(f)(std::forward(args)...)) { + -> decltype(std::mem_fn(f)(std::forward(args)...)) { return std::mem_fn(f)(std::forward(args)...); } template >{}>> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + typename = enable_if_t>::value>> + constexpr auto invoke(Fn && f, Args && ... args) noexcept( noexcept(std::forward(f)(std::forward(args)...))) - -> decltype(std::forward(f)(std::forward(args)...)) { + -> decltype(std::forward(f)(std::forward(args)...)) { return std::forward(f)(std::forward(args)...); } @@ -261,8 +292,8 @@ template struct invoke_result_impl; template struct invoke_result_impl< - F, decltype(detail::invoke(std::declval(), std::declval()...), void()), - Us...> { + F, decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { using type = decltype(detail::invoke(std::declval(), std::declval()...)); }; @@ -280,68 +311,68 @@ 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 {}; + // 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]); + 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()))); + // 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 std::false_type uses_std(...); + template + std::is_same(), std::declval())), tag> + uses_std(int); -template -struct is_std_swap_noexcept + template + struct is_std_swap_noexcept : std::integral_constant::value && - std::is_nothrow_move_assignable::value> {}; + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value> {}; -template -struct is_std_swap_noexcept : is_std_swap_noexcept {}; + template + struct is_std_swap_noexcept : is_std_swap_noexcept {}; -template -struct is_adl_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))> {}; + : 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)> {}; + : 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))> { + : 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 @@ -2421,5 +2452,4 @@ void swap(expected &lhs, } } // namespace tl -#define TL_OPTIONAL_EXPECTED_MUTEX #endif