Move is_invokeable to traits and rename it to is_invokeable_from_tuple

This commit is contained in:
Denis Blank 2018-02-06 00:12:59 +01:00
parent eafbe4b37d
commit d1e0c1d606
4 changed files with 40 additions and 30 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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.