diff --git a/include/continuable/detail/container-category.hpp b/include/continuable/detail/container-category.hpp index 359315c..2aea4c4 100644 --- a/include/continuable/detail/container-category.hpp +++ b/include/continuable/detail/container-category.hpp @@ -31,8 +31,6 @@ #ifndef CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED #define CONTINUABLE_DETAIL_CONTAINER_CATEGORY_HPP_INCLUDED -#include - namespace cti { namespace detail { namespace traversal { diff --git a/include/continuable/detail/traits.hpp b/include/continuable/detail/traits.hpp index 842a240..9ea0c10 100644 --- a/include/continuable/detail/traits.hpp +++ b/include/continuable/detail/traits.hpp @@ -408,6 +408,35 @@ constexpr auto merge(identity /*left*/, std::forward(rest)...); } +namespace detail { +template > +struct is_invokable_impl : std::common_type {}; + +template +struct is_invokable_impl< + T, std::tuple, + void_t()(std::declval()...))>> + : std::common_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> +/// ``` +template +using is_invokable_from_tuple = + typename detail::is_invokable_impl::type; + +// Checks whether the given callable object is invocable with the given +// arguments. This doesn't take member functions into account! +template +using is_invocable = is_invokable_from_tuple>; + /// Deduces to a std::false_type template using fail = std::integral_constant::value>; @@ -415,6 +444,7 @@ using fail = std::integral_constant::value>; #ifdef CONTINUABLE_HAS_CXX17_DISJUNCTION using std::disjunction; #else +namespace detail { /// Declares a C++14 polyfill for C++17 std::disjunction. template > struct disjunction_impl : std::common_type {}; @@ -422,8 +452,10 @@ template struct disjunction_impl, void_t...>> : std::common_type {}; +} // namespace detail + template -using disjunction = disjunction_impl>; +using disjunction = typename detail::disjunction_impl>::type; #endif // CONTINUABLE_HAS_CXX17_DISJUNCTION } // namespace traits diff --git a/include/continuable/detail/traverse.hpp b/include/continuable/detail/traverse.hpp index 823a2b4..fdc1522 100644 --- a/include/continuable/detail/traverse.hpp +++ b/include/continuable/detail/traverse.hpp @@ -304,7 +304,8 @@ template struct has_push_back : std::false_type {}; template struct has_push_back< - T, E, std::void_t().push_back(std::declval()))>> + T, E, + traits::void_t().push_back(std::declval()))>> : std::true_type {}; /// Specialization for a container with a single type T @@ -554,7 +555,7 @@ struct tuple_like_remapper, template auto operator()(Args&&... args) - -> std::void_t::type...> { + -> traits::void_t::type...> { int dummy[] = {0, ((void)mapper_(std::forward(args)), 0)...}; (void)dummy; } diff --git a/include/continuable/detail/util.hpp b/include/continuable/detail/util.hpp index 452cad0..81fb45a 100644 --- a/include/continuable/detail/util.hpp +++ b/include/continuable/detail/util.hpp @@ -48,29 +48,6 @@ template void unused(T&&...) { } -namespace detail { -template > -struct is_invokable_impl : std::common_type {}; - -template -struct is_invokable_impl< - T, std::tuple, - traits::void_t()(std::declval()...))>> - : std::common_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> -/// ``` -template -using is_invokable = typename detail::is_invokable_impl::type; - namespace detail { /// Forwards every element in the tuple except the last one template @@ -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 is_invokable; + traits::is_invokable_from_tuple + is_invokable; return partial_invoke_impl(is_invokable, std::forward(callable), std::move(next)); @@ -150,7 +128,8 @@ auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable, template /*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> is_invokable; + traits::is_invokable_from_tuple> + 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.