diff --git a/include/continuable/detail/traverse.hpp b/include/continuable/detail/traverse.hpp index 5257575..e0b58d4 100644 --- a/include/continuable/detail/traverse.hpp +++ b/include/continuable/detail/traverse.hpp @@ -215,7 +215,6 @@ constexpr auto map_spread(C&& callable, T&&... args) -> decltype(apply_spread_impl(is_any_spread_t{}, std::forward(callable), std::forward(args)...)) { - // Check whether any of the args is a detail::flatted_tuple_t, // if not, use the linear called version for better // compilation speed. @@ -692,10 +691,20 @@ class mapping_helper : protected mapping_strategy_base { return mapper_(std::forward(element)); } + /// SFINAE helper for plain elements not satisfying the tuple like + /// or container requirements. + /// + /// We use the proxy function invoke_mapper here, + /// because some compilers (MSVC) tend to instantiate the invocation + /// before matching the tag, which leads to build failures. + template + auto match(container_category_tag, T&& element) -> decltype( + std::declval().invoke_mapper(std::forward(element))); + /// SFINAE helper for elements satisfying the container /// requirements, which are not tuple like. template - auto deep_map(container_category_tag, T&& container) + auto match(container_category_tag, T&& container) -> decltype(container_remapping::remap(Strategy{}, std::forward(container), std::declval())); @@ -703,33 +712,42 @@ class mapping_helper : protected mapping_strategy_base { /// SFINAE helper for elements which are tuple like and /// that also may satisfy the container requirements template - auto deep_map(container_category_tag, T&& tuple_like) + auto match(container_category_tag, T&& tuple_like) -> decltype(tuple_like_remapping::remap(Strategy{}, std::forward(tuple_like), std::declval())); - /// SFINAE helper for plain elements not satisfying the tuple like - /// or container requirements. + /// This method implements the functionality for routing + /// elements through, that aren't accepted by the mapper. + /// Since the real matcher methods below are failing through SFINAE, + /// the compiler will try to specialize this function last, + /// since it's the least concrete one. + /// This works recursively, so we only call the mapper + /// with the minimal needed set of accepted arguments. + template + auto try_match(MatcherTag, T&& element) -> decltype( + std::declval().may_void(std::forward(element))) { + return this->may_void(std::forward(element)); + } + + /// Match plain elements not satisfying the tuple like or + /// container requirements. /// /// We use the proxy function invoke_mapper here, /// because some compilers (MSVC) tend to instantiate the invocation /// before matching the tag, which leads to build failures. - template - auto map(container_category_tag, T&& element) - -> decltype(std::declval().invoke_mapper( - std::forward(element))); - - /// SFINAE helper for forwarding the input to the deep remap methods in order - /// to prioritize the mapper before deep container remaps. - template - auto map(Category category, T&& element) - -> decltype(std::declval().deep_map( - category, std::forward(element))); + template + auto try_match(container_category_tag, T&& element) -> decltype( + std::declval().invoke_mapper(std::forward(element))) { + // T could be any non container or non tuple like type here, + // take int or hpx::future as an example. + return invoke_mapper(std::forward(element)); + } /// Match elements satisfying the container requirements, /// which are not tuple like. template - auto try_deep_map(container_category_tag, T&& container) + auto try_match(container_category_tag, T&& container) -> decltype(container_remapping::remap(Strategy{}, std::forward(container), std::declval())) { @@ -741,7 +759,7 @@ class mapping_helper : protected mapping_strategy_base { /// satisfy the container requirements /// -> We match tuple like types over container like ones template - auto try_deep_map(container_category_tag, T&& tuple_like) + auto try_match(container_category_tag, T&& tuple_like) -> decltype(tuple_like_remapping::remap(Strategy{}, std::forward(tuple_like), std::declval())) { @@ -749,63 +767,27 @@ class mapping_helper : protected mapping_strategy_base { try_traversor{this}); } - /// This method implements the functionality for routing - /// elements through, that aren't accepted by the mapper. - /// Since the real matcher methods below are failing through SFINAE, - /// the compiler will try to specialize this function last, - /// since it's the least concrete one. - /// This works recursively, so we only call the mapper - /// with the minimal needed set of accepted arguments. - template - auto try_deep_map(MatcherTag, T&& element) -> decltype( - std::declval().may_void(std::forward(element))) { - return this->may_void(std::forward(element)); - } - - /// Prioritize the mapper over container remapping. - /// - /// We use the proxy function invoke_mapper here, - /// because some compilers (MSVC) tend to instantiate the invocation - /// before matching the tag, which leads to build failures. - template - auto try_map(container_category_tag, T&& element) - -> decltype(std::declval().invoke_mapper( - std::forward(element))) { - // T could be any non container or non tuple like type here, - // take int or std::future as an example. - return invoke_mapper(std::forward(element)); - } - - /// Forward the input to the deep remap methods in order - /// to prioritize the mapper before deep container remaps. - template - auto try_map(Category category, T&& element) - -> decltype(std::declval().try_deep_map( - category, std::forward(element))) { - return try_deep_map(category, std::forward(element)); - } - /// Traverses a single element. /// /// SFINAE helper: Doesn't allow routing through elements, /// that aren't accepted by the mapper template auto traverse(Strategy, T&& element) - -> decltype(std::declval().map( + -> decltype(std::declval().match( std::declval::type>>(), std::declval())); /// \copybrief traverse template auto try_traverse(Strategy, T&& element) - -> decltype(std::declval().try_map( + -> decltype(std::declval().try_match( std::declval::type>>(), std::declval())) { // We use tag dispatching here, to categorize the type T whether // it satisfies the container or tuple like requirements. // Then we can choose the underlying implementation accordingly. - return try_map(container_category_of_t::type>{}, - std::forward(element)); + return try_match(container_category_of_t::type>{}, + std::forward(element)); } public: diff --git a/test/unit-test/single/test-continuable-traverse.cpp b/test/unit-test/single/test-continuable-traverse.cpp index bbe3c64..d741563 100644 --- a/test/unit-test/single/test-continuable-traverse.cpp +++ b/test/unit-test/single/test-continuable-traverse.cpp @@ -44,9 +44,7 @@ using cti::spread_this; using cti::traverse_pack; struct all_map_float { - template < - typename T, - std::enable_if_t>::value>* = nullptr> + template float operator()(T el) const { return float(el + 1.f); } @@ -61,7 +59,8 @@ struct my_mapper { }; struct all_map { - int operator()(int) const { + template + int operator()(T) const { return 0; } }; @@ -281,9 +280,7 @@ public: explicit counter_mapper(int& counter) : counter_(counter) { } - template >::value || - std::is_empty>::value>* = nullptr> + template void operator()(T) const { ++counter_.get(); } @@ -680,7 +677,8 @@ TEST(traverse_strategic_tuple_like_traverse, remap_references) { /// A mapper which duplicates the given element struct duplicate_mapper { - auto operator()(int arg) -> decltype(spread_this(arg, arg)) { + template + auto operator()(T arg) -> decltype(spread_this(arg, arg)) { return spread_this(arg, arg); } }; @@ -758,19 +756,6 @@ TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_array) { static_assert(std::is_void::value, "Failed..."); } -TEST(traversal_prio, prioritize_mapping) { - std::vector vec{0, 1, 2}; - int res = map_pack( - [](std::vector& vec) { - // ... - EXPECT_EQ(vec.size(), 3U); - return 4; - }, - vec); - - EXPECT_EQ(res, 4); -} - struct flat_tupelizing_tag1 {}; struct flat_tupelizing_tag2 {};