mirror of
https://github.com/TartanLlama/expected.git
synced 2025-07-31 09:27:18 +02:00
Tidy traits
This commit is contained in:
@ -235,24 +235,55 @@ template <class...> struct conjunction : std::true_type {};
|
|||||||
template <class B> struct conjunction<B> : B {};
|
template <class B> struct conjunction<B> : B {};
|
||||||
template <class B, class... Bs>
|
template <class B, class... Bs>
|
||||||
struct conjunction<B, Bs...>
|
struct conjunction<B, Bs...>
|
||||||
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
|
: std::conditional<bool(B::value), conjunction<Bs...>, 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 <class T> struct is_pointer_to_non_const_member_func : std::false_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...)> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...)&> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) &&> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile &> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile &&> : std::true_type {};
|
||||||
|
|
||||||
|
template <class T> struct is_const_or_const_ref : std::false_type {};
|
||||||
|
template <class T> struct is_const_or_const_ref<T const&> : std::true_type {};
|
||||||
|
template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
// std::invoke from C++17
|
// std::invoke from C++17
|
||||||
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
||||||
template <typename Fn, typename... Args,
|
template <typename Fn, typename... Args,
|
||||||
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>{}>,
|
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
|
||||||
int = 0>
|
typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value
|
||||||
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
&& is_const_or_const_ref<Args...>::value)>,
|
||||||
|
#endif
|
||||||
|
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
|
||||||
|
int = 0>
|
||||||
|
constexpr auto invoke(Fn && f, Args && ... args) noexcept(
|
||||||
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
|
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
|
||||||
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
|
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
|
||||||
return std::mem_fn(f)(std::forward<Args>(args)...);
|
return std::mem_fn(f)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fn, typename... Args,
|
template <typename Fn, typename... Args,
|
||||||
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
|
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
|
||||||
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
constexpr auto invoke(Fn && f, Args && ... args) noexcept(
|
||||||
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
||||||
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
||||||
return std::forward<Fn>(f)(std::forward<Args>(args)...);
|
return std::forward<Fn>(f)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,8 +292,8 @@ template <class F, class, class... Us> struct invoke_result_impl;
|
|||||||
|
|
||||||
template <class F, class... Us>
|
template <class F, class... Us>
|
||||||
struct invoke_result_impl<
|
struct invoke_result_impl<
|
||||||
F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
|
F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
|
||||||
Us...> {
|
Us...> {
|
||||||
using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
|
using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -280,68 +311,68 @@ template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
|
|||||||
#else
|
#else
|
||||||
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
||||||
namespace swap_adl_tests {
|
namespace swap_adl_tests {
|
||||||
// if swap ADL finds this then it would call std::swap otherwise (same
|
// if swap ADL finds this then it would call std::swap otherwise (same
|
||||||
// signature)
|
// signature)
|
||||||
struct tag {};
|
struct tag {};
|
||||||
|
|
||||||
template <class T> tag swap(T &, T &);
|
template <class T> tag swap(T&, T&);
|
||||||
template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
|
template <class T, std::size_t N> tag swap(T(&a)[N], T(&b)[N]);
|
||||||
|
|
||||||
// helper functions to test if an unqualified swap is possible, and if it
|
// helper functions to test if an unqualified swap is possible, and if it
|
||||||
// becomes std::swap
|
// becomes std::swap
|
||||||
template <class, class> std::false_type can_swap(...) noexcept(false);
|
template <class, class> std::false_type can_swap(...) noexcept(false);
|
||||||
template <class T, class U,
|
template <class T, class U,
|
||||||
class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
|
class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>
|
||||||
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
|
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(),
|
||||||
std::declval<U &>())));
|
std::declval<U&>())));
|
||||||
|
|
||||||
template <class, class> std::false_type uses_std(...);
|
template <class, class> std::false_type uses_std(...);
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
|
std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag>
|
||||||
uses_std(int);
|
uses_std(int);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct is_std_swap_noexcept
|
struct is_std_swap_noexcept
|
||||||
: std::integral_constant<bool,
|
: std::integral_constant<bool,
|
||||||
std::is_nothrow_move_constructible<T>::value &&
|
std::is_nothrow_move_constructible<T>::value&&
|
||||||
std::is_nothrow_move_assignable<T>::value> {};
|
std::is_nothrow_move_assignable<T>::value> {};
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
struct is_adl_swap_noexcept
|
struct is_adl_swap_noexcept
|
||||||
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
|
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
|
||||||
} // namespace swap_adl_tests
|
} // namespace swap_adl_tests
|
||||||
|
|
||||||
template <class T, class U = T>
|
template <class T, class U = T>
|
||||||
struct is_swappable
|
struct is_swappable
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
|
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
|
||||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
|
||||||
(std::is_move_assignable<T>::value &&
|
(std::is_move_assignable<T>::value &&
|
||||||
std::is_move_constructible<T>::value))> {};
|
std::is_move_constructible<T>::value))> {};
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
struct is_swappable<T[N], T[N]>
|
struct is_swappable<T[N], T[N]>
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
|
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
|
||||||
(!decltype(
|
(!decltype(
|
||||||
detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
|
detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
|
||||||
is_swappable<T, T>::value)> {};
|
is_swappable<T, T>::value)> {};
|
||||||
|
|
||||||
template <class T, class U = T>
|
template <class T, class U = T>
|
||||||
struct is_nothrow_swappable
|
struct is_nothrow_swappable
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
is_swappable<T, U>::value &&
|
is_swappable<T, U>::value &&
|
||||||
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
||||||
&&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
||||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
||||||
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
||||||
U>::value))> {
|
U>::value))> {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -2421,5 +2452,4 @@ void swap(expected<T, E> &lhs,
|
|||||||
}
|
}
|
||||||
} // namespace tl
|
} // namespace tl
|
||||||
|
|
||||||
#define TL_OPTIONAL_EXPECTED_MUTEX
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user