mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Move is_invokeable to traits and rename it to is_invokeable_from_tuple
This commit is contained in:
parent
eafbe4b37d
commit
d1e0c1d606
@ -31,8 +31,6 @@
|
||||
#ifndef CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED
|
||||
#define CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED
|
||||
|
||||
#include <continuable/continuable-api.hpp>
|
||||
|
||||
namespace cti {
|
||||
namespace detail {
|
||||
namespace traversal {
|
||||
|
||||
@ -408,6 +408,35 @@ constexpr auto merge(identity<LeftArgs...> /*left*/,
|
||||
std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename Args, typename = traits::void_t<>>
|
||||
struct is_invokable_impl : std::common_type<std::false_type> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_invokable_impl<
|
||||
T, std::tuple<Args...>,
|
||||
void_t<decltype(std::declval<T>()(std::declval<Args>()...))>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Deduces to a std::true_type if the given type is callable with the arguments
|
||||
/// inside the given tuple.
|
||||
/// The main reason for implementing it with the detection idiom instead of
|
||||
/// hana like detection is that MSVC has issues with capturing raw template
|
||||
/// arguments inside lambda closures.
|
||||
///
|
||||
/// ```cpp
|
||||
/// traits::is_invokable<object, std::tuple<Args...>>
|
||||
/// ```
|
||||
template <typename T, typename Args>
|
||||
using is_invokable_from_tuple =
|
||||
typename detail::is_invokable_impl<T, Args>::type;
|
||||
|
||||
// Checks whether the given callable object is invocable with the given
|
||||
// arguments. This doesn't take member functions into account!
|
||||
template <typename T, typename... Args>
|
||||
using is_invocable = is_invokable_from_tuple<T, std::tuple<Args...>>;
|
||||
|
||||
/// Deduces to a std::false_type
|
||||
template <typename T>
|
||||
using fail = std::integral_constant<bool, !std::is_same<T, T>::value>;
|
||||
@ -415,6 +444,7 @@ using fail = std::integral_constant<bool, !std::is_same<T, T>::value>;
|
||||
#ifdef CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
using std::disjunction;
|
||||
#else
|
||||
namespace detail {
|
||||
/// Declares a C++14 polyfill for C++17 std::disjunction.
|
||||
template <typename Args, typename = void_t<>>
|
||||
struct disjunction_impl : std::common_type<std::false_type> {};
|
||||
@ -422,8 +452,10 @@ template <typename... Args>
|
||||
struct disjunction_impl<identity<Args...>,
|
||||
void_t<std::enable_if_t<bool(Args::value)>...>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Args>
|
||||
using disjunction = disjunction_impl<identity<Args...>>;
|
||||
using disjunction = typename detail::disjunction_impl<identity<Args...>>::type;
|
||||
#endif // CONTINUABLE_HAS_CXX17_DISJUNCTION
|
||||
|
||||
} // namespace traits
|
||||
|
||||
@ -304,7 +304,8 @@ template <typename T, typename E, typename = void>
|
||||
struct has_push_back : std::false_type {};
|
||||
template <typename T, typename E>
|
||||
struct has_push_back<
|
||||
T, E, std::void_t<decltype(std::declval<T>().push_back(std::declval<E>()))>>
|
||||
T, E,
|
||||
traits::void_t<decltype(std::declval<T>().push_back(std::declval<E>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
/// Specialization for a container with a single type T
|
||||
@ -554,7 +555,7 @@ struct tuple_like_remapper<strategy_traverse_tag, M, Base<OldArgs...>,
|
||||
|
||||
template <typename... Args>
|
||||
auto operator()(Args&&... args)
|
||||
-> std::void_t<typename invoke_result<M, OldArgs>::type...> {
|
||||
-> traits::void_t<typename invoke_result<M, OldArgs>::type...> {
|
||||
int dummy[] = {0, ((void)mapper_(std::forward<Args>(args)), 0)...};
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
@ -48,29 +48,6 @@ template <typename... T>
|
||||
void unused(T&&...) {
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename Args, typename = traits::void_t<>>
|
||||
struct is_invokable_impl : std::common_type<std::false_type> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_invokable_impl<
|
||||
T, std::tuple<Args...>,
|
||||
traits::void_t<decltype(std::declval<T>()(std::declval<Args>()...))>>
|
||||
: std::common_type<std::true_type> {};
|
||||
} // namespace detail
|
||||
|
||||
/// Deduces to a std::true_type if the given type is callable with the arguments
|
||||
/// inside the given tuple.
|
||||
/// The main reason for implementing it with the detection idiom instead of
|
||||
/// hana like detection is that MSVC has issues with capturing raw template
|
||||
/// arguments inside lambda closures.
|
||||
///
|
||||
/// ```cpp
|
||||
/// traits::is_invokable<object, std::tuple<Args...>>
|
||||
/// ```
|
||||
template <typename T, typename Args>
|
||||
using is_invokable = typename detail::is_invokable_impl<T, Args>::type;
|
||||
|
||||
namespace detail {
|
||||
/// Forwards every element in the tuple except the last one
|
||||
template <typename T>
|
||||
@ -117,7 +94,8 @@ auto partial_invoke_impl(std::false_type, T&& callable,
|
||||
auto next = forward_except_last(std::move(args));
|
||||
|
||||
// Test whether we are able to call the function with the given tuple
|
||||
is_invokable<decltype(callable), decltype(next)> is_invokable;
|
||||
traits::is_invokable_from_tuple<decltype(callable), decltype(next)>
|
||||
is_invokable;
|
||||
|
||||
return partial_invoke_impl(is_invokable, std::forward<T>(callable),
|
||||
std::move(next));
|
||||
@ -150,7 +128,8 @@ auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
|
||||
template <typename T, typename... Args>
|
||||
/*keep this inline*/ inline auto partial_invoke(T&& callable, Args&&... args) {
|
||||
// Test whether we are able to call the function with the given arguments.
|
||||
is_invokable<decltype(callable), std::tuple<Args...>> is_invokable;
|
||||
traits::is_invokable_from_tuple<decltype(callable), std::tuple<Args...>>
|
||||
is_invokable;
|
||||
|
||||
// The implementation is done in a shortcut way so there are less
|
||||
// type instantiations needed to call the callable with its full signature.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user