This is a follow-up question for A recursive_transform for std::vector with various return type and A recursive_transform Template Function Implementation with std::invocable concept in C++. Besides the recursive version std::ranges::transform
, I am trying to implement a recursive version std::ranges::copy_if
.
The experimental implementation
The experimental implementation is as below.
// recursive_copy_if function template <std::ranges::input_range Range, std::invocable<std::ranges::range_value_t<Range>> UnaryPredicate> constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate) { Range output{}; std::ranges::copy_if(std::ranges::cbegin(input), std::ranges::cend(input), std::inserter(output, std::ranges::end(output)), unary_predicate); return output; } template < std::ranges::input_range Range, class UnaryPredicate> requires (!std::invocable<UnaryPredicate, std::ranges::range_value_t<Range>>) constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate) { Range output{}; std::ranges::transform( std::ranges::cbegin(input), std::ranges::cend(input), std::inserter(output, std::ranges::end(output)), [&unary_predicate](auto&& element) { return recursive_copy_if(element, unary_predicate); } ); return output; }
Test cases
// std::vector<int> std::vector<int> test_vector = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_copy_if(test_vector, [](int x) { return (x % 2) == 0; })); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2 = { test_vector, test_vector, test_vector }; recursive_print(recursive_copy_if(test_vector2, [](int x) { return (x % 2) == 0; })); // std::vector<std::string> recursive_print( recursive_copy_if( recursive_transform(test_vector, [](int x) { return std::to_string(x); }), [](std::string x) { return (x == "1"); } ) ); // std::vector<std::vector<std::string>> recursive_print( recursive_copy_if( recursive_transform(test_vector2, [](int x) { return std::to_string(x); }), [](std::string x) { return (x == "1"); } ) ); // std::deque<int> std::deque<int> test_deque; test_deque.push_back(1); test_deque.push_back(2); test_deque.push_back(3); test_deque.push_back(4); test_deque.push_back(5); test_deque.push_back(6); recursive_print(recursive_copy_if(test_deque, [](int x) { return (x % 2) == 0; })); // std::deque<std::deque<int>> std::deque<decltype(test_deque)> test_deque2; test_deque2.push_back(test_deque); test_deque2.push_back(test_deque); test_deque2.push_back(test_deque); recursive_print(recursive_copy_if(test_deque2, [](int x) { return (x % 2) == 0; })); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_copy_if(test_list, [](int x) { return (x % 2) == 0; })); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_copy_if(test_list2, [](int x) { return (x % 2) == 0; }));
Full Testing Code The full testing code:
#include <algorithm> #include <array> #include <cassert> #include <chrono> #include <complex> #include <concepts> #include <deque> #include <execution> #include <exception> #include <functional> #include <iostream> #include <iterator> #include <list> #include <map> #include <mutex> #include <numeric> #include <optional> #include <ranges> #include <stdexcept> #include <string> #include <tuple> #include <type_traits> #include <utility> #include <variant> #include <vector> // recursive_copy_if function template <std::ranges::input_range Range, std::invocable<std::ranges::range_value_t<Range>> UnaryPredicate> constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate) { Range output{}; std::ranges::copy_if(std::ranges::cbegin(input), std::ranges::cend(input), std::inserter(output, std::ranges::end(output)), unary_predicate); return output; } template < std::ranges::input_range Range, class UnaryPredicate> requires (!std::invocable<UnaryPredicate, std::ranges::range_value_t<Range>>) constexpr auto recursive_copy_if(const Range& input, const UnaryPredicate& unary_predicate) { Range output{}; std::ranges::transform( std::ranges::cbegin(input), std::ranges::cend(input), std::inserter(output, std::ranges::end(output)), [&unary_predicate](auto&& element) { return recursive_copy_if(element, unary_predicate); } ); return output; } // recursive_print implementation // https://codereview.stackexchange.com/q/251208/231235 template<std::ranges::input_range Range> constexpr auto recursive_print(const Range& input, const int level = 0) { auto output = input; std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl; std::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output), [level](auto&& x) { std::cout << std::string(level, ' ') << x << std::endl; return x; } ); return output; } template<std::ranges::input_range Range> requires (std::ranges::input_range<std::ranges::range_value_t<Range>>) constexpr auto recursive_print(const Range& input, const int level = 0) { auto output = input; std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl; std::transform(std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output), [level](auto&& element) { return recursive_print(element, level + 1); } ); return output; } // recursive_invoke_result_t implementation template<typename, typename> struct recursive_invoke_result { }; template<typename T, std::invocable<T> F> struct recursive_invoke_result<F, T> { using type = std::invoke_result_t<F, T>; }; template<typename F, template<typename...> typename Container, typename... Ts> requires ( !std::invocable<F, Container<Ts...>> && std::ranges::input_range<Container<Ts...>> && requires { typename recursive_invoke_result<F, std::ranges::range_value_t<Container<Ts...>>>::type; }) struct recursive_invoke_result<F, Container<Ts...>> { using type = Container<typename recursive_invoke_result<F, std::ranges::range_value_t<Container<Ts...>>>::type>; }; template<typename F, typename T> using recursive_invoke_result_t = typename recursive_invoke_result<F, T>::type; // recursive_transform implementation template <class T, std::invocable<T> F> constexpr auto recursive_transform(const T& input, const F& f) { return f(input); } template < std::ranges::input_range Range, class F> requires (!std::invocable<F, Range>) constexpr auto recursive_transform(const Range& input, const F& f) { recursive_invoke_result_t<F, Range> output{}; std::ranges::transform( std::ranges::cbegin(input), std::ranges::cend(input), std::inserter(output, std::ranges::end(output)), [&f](auto&& element) { return recursive_transform(element, f); } ); return output; } int main() { // std::vector<int> std::vector<int> test_vector = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_copy_if(test_vector, [](int x) { return (x % 2) == 0; })); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2 = { test_vector, test_vector, test_vector }; recursive_print(recursive_copy_if(test_vector2, [](int x) { return (x % 2) == 0; })); // std::vector<std::string> recursive_print( recursive_copy_if( recursive_transform(test_vector, [](int x) { return std::to_string(x); }), [](std::string x) { return (x == "1"); } ) ); // std::vector<std::vector<std::string>> recursive_print( recursive_copy_if( recursive_transform(test_vector2, [](int x) { return std::to_string(x); }), [](std::string x) { return (x == "1"); } ) ); // std::deque<int> std::deque<int> test_deque; test_deque.push_back(1); test_deque.push_back(2); test_deque.push_back(3); test_deque.push_back(4); test_deque.push_back(5); test_deque.push_back(6); recursive_print(recursive_copy_if(test_deque, [](int x) { return (x % 2) == 0; })); // std::deque<std::deque<int>> std::deque<decltype(test_deque)> test_deque2; test_deque2.push_back(test_deque); test_deque2.push_back(test_deque); test_deque2.push_back(test_deque); recursive_print(recursive_copy_if(test_deque2, [](int x) { return (x % 2) == 0; })); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_copy_if(test_list, [](int x) { return (x % 2) == 0; })); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_copy_if(test_list2, [](int x) { return (x % 2) == 0; })); return 0; }
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A recursive_transform for std::vector with various return type and
A recursive_transform Template Function Implementation with std::invocable concept in C++
What changes has been made in the code since last question?
The implementation of
recursive_copy_if
template function is the main idea in this question.Why a new review is being asked for?
If there is any possible improvement, please let me know.