This is a follow-up question for A recursive_replace_if Template Function Implementation in C++, A recursive_copy_if Template Function Implementation in C++, A recursive_count_if Function with Unwrap Level for Various Type Arbitrary Nested Iterable Implementation in C++ and A recursive_count_if Function For Various Type Arbitrary Nested Iterable Implementation in C++. After implemented recursive_replace_if
and recursive_copy_if
, I am trying to generalize the operation of applying a function on elements in nested container. The unwrap level parameter is used here instead of std::invocable
as the termination condition of the recursion process.
The experimental implementation
The experimental implementation is as below.
// recursive_function_applier implementation
template<std::size_t unwrap_level, class F, std::ranges::range Range, class... Args>
constexpr auto recursive_function_applier(const F& function, const Range& input, Args... args)
{
if constexpr (unwrap_level >= 1)
{
Range output{};
std::ranges::transform(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
[&function, &args...](auto&& element) { return recursive_function_applier<unwrap_level - 1>(function, element, args...); }
);
return output;
}
else
{
Range output{};
function(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
args...);
return output;
}
}
Test cases
Test cases with using
std::ranges::copy
function// std::copy test cases // std::vector<int> std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 }; recursive_print(recursive_function_applier<0>(std::ranges::copy, test_vector)); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector }; recursive_print(recursive_function_applier<1>(std::ranges::copy, test_vector2)); // std::vector<std::string> std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; recursive_print( recursive_function_applier<0>( std::ranges::copy, test_string_vector ) ); // std::vector<std::vector<std::string>> std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector }; recursive_print( recursive_function_applier<1>( std::ranges::copy, test_string_vector2 ) ); // 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_function_applier<0>(std::ranges::copy, test_deque)); // 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_function_applier<1>(std::ranges::copy, test_deque2)); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_function_applier<0>(std::ranges::copy, test_list)); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_function_applier<1>(std::ranges::copy, test_list2)); recursive_print( recursive_function_applier<10>( std::ranges::copy, n_dim_container_generator<10, std::list>(test_list, 3) ) );
Test cases with using
std::ranges::replace_copy_if
function// std::ranges::replace_copy_if test cases // std::vector<int> std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 }; recursive_print(recursive_function_applier<0>(std::ranges::replace_copy_if, test_vector, std::bind(std::less<int>(), std::placeholders::_1, 5), 55)); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector }; recursive_print(recursive_function_applier<1>(std::ranges::replace_copy_if, test_vector2, std::bind(std::less<int>(), std::placeholders::_1, 5), 55)); // std::vector<std::string> std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; recursive_print( recursive_function_applier<0>( std::ranges::replace_copy_if, test_string_vector, [](std::string x) { return (x == "1"); }, "11" ) ); // std::vector<std::vector<std::string>> std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector }; recursive_print( recursive_function_applier<1>( std::ranges::replace_copy_if, test_string_vector2, [](std::string x) { return (x == "1"); }, "11" ) ); // 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_function_applier<0>(std::ranges::replace_copy_if, test_deque, [](int x) { return (x % 2) == 0; }, 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_function_applier<1>(std::ranges::replace_copy_if, test_deque2, [](int x) { return (x % 2) == 0; }, 0)); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_function_applier<0>(std::ranges::replace_copy_if, test_list, [](int x) { return (x % 2) == 0; }, 0)); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_function_applier<1>(std::ranges::replace_copy_if, test_list2, [](int x) { return (x % 2) == 0; }, 0)); recursive_print( recursive_function_applier<10>( std::ranges::replace_copy_if, n_dim_container_generator<10, std::list>(test_list, 3), [](int x) { return (x % 2) == 0; }, 0 ) );
Test cases with using
std::ranges::remove_copy
function// std::remove_copy test cases // std::vector<int> std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 }; recursive_print(recursive_function_applier<0>(std::ranges::remove_copy, test_vector, 5)); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector }; recursive_print(recursive_function_applier<1>(std::ranges::remove_copy, test_vector2, 5)); // std::vector<std::string> std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; recursive_print( recursive_function_applier<0>( std::ranges::remove_copy, test_string_vector, "0" ) ); // std::vector<std::vector<std::string>> std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector }; recursive_print( recursive_function_applier<1>( std::ranges::remove_copy, test_string_vector2, "0" ) ); // 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_function_applier<0>(std::ranges::remove_copy, test_deque, 1)); // 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_function_applier<1>(std::ranges::remove_copy, test_deque2, 1)); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_function_applier<0>(std::ranges::remove_copy, test_list, 1)); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_function_applier<1>(std::ranges::remove_copy, test_list2, 1)); recursive_print( recursive_function_applier<10>( std::ranges::remove_copy, n_dim_container_generator<10, std::list>(test_list, 3), 1 ) );
Test cases with using
std::ranges::remove_copy_if
function// std::remove_copy_if test cases // std::vector<int> std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 }; recursive_print(recursive_function_applier<0>(std::ranges::remove_copy_if, test_vector, std::bind(std::less<int>(), std::placeholders::_1, 5))); // std::vector<std::vector<int>> std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector }; recursive_print(recursive_function_applier<1>(std::ranges::remove_copy_if, test_vector2, std::bind(std::less<int>(), std::placeholders::_1, 5))); // std::vector<std::string> std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; recursive_print( recursive_function_applier<0>( std::ranges::remove_copy_if, test_string_vector, [](std::string x) { return (x == "0"); } ) ); // std::vector<std::vector<std::string>> std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector }; recursive_print( recursive_function_applier<1>( std::ranges::remove_copy_if, test_string_vector2, [](std::string x) { return (x == "0"); } ) ); // 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_function_applier<0>(std::ranges::remove_copy_if, test_deque, std::bind(std::less<int>(), std::placeholders::_1, 5))); // 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_function_applier<1>(std::ranges::remove_copy_if, test_deque2, std::bind(std::less<int>(), std::placeholders::_1, 5))); // std::list<int> std::list<int> test_list = { 1, 2, 3, 4, 5, 6 }; recursive_print(recursive_function_applier<0>(std::ranges::remove_copy_if, test_list, std::bind(std::less<int>(), std::placeholders::_1, 5))); // std::list<std::list<int>> std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list }; recursive_print(recursive_function_applier<1>(std::ranges::remove_copy_if, test_list2, std::bind(std::less<int>(), std::placeholders::_1, 5))); recursive_print( recursive_function_applier<5>( std::ranges::remove_copy_if, n_dim_container_generator<5, std::list>(test_list, 3), std::bind(std::less<int>(), std::placeholders::_1, 5) ) );
The full testing code:
// A Function Applier for Applying Various Algorithms on Nested Container Things in C++
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <complex>
#include <concepts>
#include <deque>
#include <exception>
#include <execution>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <numeric>
#include <optional>
#include <ranges>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
template<typename T>
concept is_inserterable = requires(T x)
{
std::inserter(x, std::ranges::end(x));
};
#ifdef USE_BOOST_MULTIDIMENSIONAL_ARRAY
template<typename T>
concept is_multi_array = requires(T x)
{
x.num_dimensions();
x.shape();
boost::multi_array(x);
};
#endif
// 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>
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_count implementation
template<std::ranges::input_range Range, typename T>
constexpr auto recursive_count(const Range& input, const T& target)
{
return std::count(std::ranges::cbegin(input), std::ranges::cend(input), target);
}
// transform_reduce version
template<std::ranges::input_range Range, typename T>
requires std::ranges::input_range<std::ranges::range_value_t<Range>>
constexpr auto recursive_count(const Range& input, const T& target)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [target](auto&& element) {
return recursive_count(element, target);
});
}
// recursive_count implementation (with execution policy)
template<class ExPo, std::ranges::input_range Range, typename T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr auto recursive_count(ExPo execution_policy, const Range& input, const T& target)
{
return std::count(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), target);
}
template<class ExPo, std::ranges::input_range Range, typename T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (std::ranges::input_range<std::ranges::range_value_t<Range>>)
constexpr auto recursive_count(ExPo execution_policy, const Range& input, const T& target)
{
return std::transform_reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [execution_policy, target](auto&& element) {
return recursive_count(execution_policy, element, target);
});
}
// recursive_count_if implementation
template<class T, std::invocable<T> Pred>
constexpr std::size_t recursive_count_if(const T& input, const Pred& predicate)
{
return predicate(input) ? 1 : 0;
}
template<std::ranges::input_range Range, class Pred>
requires (!std::invocable<Pred, Range>)
constexpr auto recursive_count_if(const Range& input, const Pred& predicate)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if(element, predicate);
});
}
// recursive_count_if implementation (with execution policy)
template<class ExPo, class T, std::invocable<T> Pred>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr std::size_t recursive_count_if(ExPo execution_policy, const T& input, const Pred& predicate)
{
return predicate(input) ? 1 : 0;
}
template<class ExPo, std::ranges::input_range Range, class Pred>
requires ((std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (!std::invocable<Pred, Range>))
constexpr auto recursive_count_if(ExPo execution_policy, const Range& input, const Pred& predicate)
{
return std::transform_reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if(element, predicate);
});
}
// recursive_count_if implementation (the version with unwrap_level)
template<std::size_t unwrap_level, std::ranges::range T, class Pred>
auto recursive_count_if(const T& input, const Pred& predicate)
{
if constexpr (unwrap_level > 1)
{
return std::transform_reduce(std::ranges::cbegin(input), std::ranges::cend(input), std::size_t{}, std::plus<std::size_t>(), [predicate](auto&& element) {
return recursive_count_if<unwrap_level - 1>(element, predicate);
});
}
else
{
return std::count_if(std::ranges::cbegin(input), std::ranges::cend(input), predicate);
}
}
// recursive_function_applier implementation
template<std::size_t unwrap_level, class F, std::ranges::range Range, class... Args>
constexpr auto recursive_function_applier(const F& function, const Range& input, Args... args)
{
if constexpr (unwrap_level >= 1)
{
Range output{};
std::ranges::transform(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
[&function, &args...](auto&& element) { return recursive_function_applier<unwrap_level - 1>(function, element, args...); }
);
return output;
}
else
{
Range output{};
function(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
args...);
return output;
}
}
// recursive_print implementation
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::ranges::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::ranges::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_replace_copy_if implementation
template<std::ranges::range Range, std::invocable<std::ranges::range_value_t<Range>> UnaryPredicate, class T>
constexpr auto recursive_replace_copy_if(const Range& input, const UnaryPredicate& unary_predicate, const T& new_value)
{
Range output{};
std::ranges::replace_copy_if(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
unary_predicate,
new_value);
return output;
}
template<std::ranges::input_range Range, class UnaryPredicate, class T>
requires (!std::invocable<UnaryPredicate, std::ranges::range_value_t<Range>>)
constexpr auto recursive_replace_copy_if(const Range& input, const UnaryPredicate& unary_predicate, const T& new_value)
{
Range output{};
std::ranges::transform(
std::ranges::cbegin(input),
std::ranges::cend(input),
std::inserter(output, std::ranges::end(output)),
[&unary_predicate, &new_value](auto&& element) { return recursive_replace_copy_if(element, unary_predicate, new_value); }
);
return output;
}
// recursive_size implementation
template<class T> requires (!std::ranges::range<T>)
constexpr auto recursive_size(const T& input)
{
return 1;
}
template<std::ranges::range Range> requires (!(std::ranges::input_range<std::ranges::range_value_t<Range>>))
constexpr auto recursive_size(const Range& input)
{
return std::ranges::size(input);
}
template<std::ranges::range Range> requires (std::ranges::input_range<std::ranges::range_value_t<Range>>)
constexpr auto recursive_size(const Range& input)
{
return std::transform_reduce(std::ranges::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [](auto& element) {
return recursive_size(element);
});
}
// recursive_transform implementation
// recursive_invoke_result_t implementation
// from https://stackoverflow.com/a/65504127/6667035
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;
template <std::ranges::range Range>
constexpr auto get_output_iterator(Range& output)
{
return std::inserter(output, std::ranges::end(output));
}
template <class T, std::invocable<T> F>
constexpr auto recursive_transform(const T& input, const F& f)
{
return std::invoke(f, input); // use std::invoke() instead, https://codereview.stackexchange.com/a/283364/231235
}
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;
}
template<std::size_t dim, class T>
constexpr auto n_dim_vector_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_vector_generator<dim - 1>(input, times);
std::vector<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, std::size_t times, class T>
constexpr auto n_dim_array_generator(T input)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_array_generator<dim - 1, times>(input);
std::array<decltype(element), times> output;
std::fill(std::begin(output), std::end(output), element);
return output;
}
}
template<std::size_t dim, class T>
constexpr auto n_dim_deque_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_deque_generator<dim - 1>(input, times);
std::deque<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, class T>
constexpr auto n_dim_list_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
auto element = n_dim_list_generator<dim - 1>(input, times);
std::list<decltype(element)> output(times, element);
return output;
}
}
template<std::size_t dim, template<class...> class Container = std::vector, class T>
constexpr auto n_dim_container_generator(T input, std::size_t times)
{
if constexpr (dim == 0)
{
return input;
}
else
{
return Container(times, n_dim_container_generator<dim - 1, Container, T>(input, times));
}
}
void copy_test();
void replace_copy_if_test();
void remove_copy_test();
void remove_copy_if_test();
int main()
{
copy_test();
replace_copy_if_test();
remove_copy_test();
remove_copy_if_test();
return 0;
}
void copy_test()
{
// std::copy test cases
// std::vector<int>
std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
recursive_print(recursive_function_applier<0>(std::ranges::copy, test_vector));
// std::vector<std::vector<int>>
std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector };
recursive_print(recursive_function_applier<1>(std::ranges::copy, test_vector2));
// std::vector<std::string>
std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" };
recursive_print(
recursive_function_applier<0>(
std::ranges::copy, test_string_vector
)
);
// std::vector<std::vector<std::string>>
std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector };
recursive_print(
recursive_function_applier<1>(
std::ranges::copy, test_string_vector2
)
);
// 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_function_applier<0>(std::ranges::copy, test_deque));
// 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_function_applier<1>(std::ranges::copy, test_deque2));
// std::list<int>
std::list<int> test_list = { 1, 2, 3, 4, 5, 6 };
recursive_print(recursive_function_applier<0>(std::ranges::copy, test_list));
// std::list<std::list<int>>
std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list };
recursive_print(recursive_function_applier<1>(std::ranges::copy, test_list2));
recursive_print(
recursive_function_applier<5>(
std::ranges::copy,
n_dim_container_generator<5, std::list>(test_list, 3)
)
);
return;
}
void replace_copy_if_test()
{
// std::ranges::replace_copy_if test cases
// std::vector<int>
std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
recursive_print(recursive_function_applier<0>(std::ranges::replace_copy_if, test_vector, std::bind(std::less<int>(), std::placeholders::_1, 5), 55));
// std::vector<std::vector<int>>
std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector };
recursive_print(recursive_function_applier<1>(std::ranges::replace_copy_if, test_vector2, std::bind(std::less<int>(), std::placeholders::_1, 5), 55));
// std::vector<std::string>
std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" };
recursive_print(
recursive_function_applier<0>(
std::ranges::replace_copy_if, test_string_vector, [](std::string x) { return (x == "1"); }, "11"
)
);
// std::vector<std::vector<std::string>>
std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector };
recursive_print(
recursive_function_applier<1>(
std::ranges::replace_copy_if, test_string_vector2, [](std::string x) { return (x == "1"); }, "11"
)
);
// 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_function_applier<0>(std::ranges::replace_copy_if, test_deque, [](int x) { return (x % 2) == 0; }, 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_function_applier<1>(std::ranges::replace_copy_if, test_deque2, [](int x) { return (x % 2) == 0; }, 0));
// std::list<int>
std::list<int> test_list = { 1, 2, 3, 4, 5, 6 };
recursive_print(recursive_function_applier<0>(std::ranges::replace_copy_if, test_list, [](int x) { return (x % 2) == 0; }, 0));
// std::list<std::list<int>>
std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list };
recursive_print(recursive_function_applier<1>(std::ranges::replace_copy_if, test_list2, [](int x) { return (x % 2) == 0; }, 0));
recursive_print(
recursive_function_applier<5>(
std::ranges::replace_copy_if,
n_dim_container_generator<5, std::list>(test_list, 3),
[](int x) { return (x % 2) == 0; },
0
)
);
return;
}
void remove_copy_test()
{
// std::remove_copy test cases
// std::vector<int>
std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
recursive_print(recursive_function_applier<0>(std::ranges::remove_copy, test_vector, 5));
// std::vector<std::vector<int>>
std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector };
recursive_print(recursive_function_applier<1>(std::ranges::remove_copy, test_vector2, 5));
// std::vector<std::string>
std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" };
recursive_print(
recursive_function_applier<0>(
std::ranges::remove_copy, test_string_vector, "0"
)
);
// std::vector<std::vector<std::string>>
std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector };
recursive_print(
recursive_function_applier<1>(
std::ranges::remove_copy, test_string_vector2, "0"
)
);
// 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_function_applier<0>(std::ranges::remove_copy, test_deque, 1));
// 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_function_applier<1>(std::ranges::remove_copy, test_deque2, 1));
// std::list<int>
std::list<int> test_list = { 1, 2, 3, 4, 5, 6 };
recursive_print(recursive_function_applier<0>(std::ranges::remove_copy, test_list, 1));
// std::list<std::list<int>>
std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list };
recursive_print(recursive_function_applier<1>(std::ranges::remove_copy, test_list2, 1));
recursive_print(
recursive_function_applier<5>(
std::ranges::remove_copy,
n_dim_container_generator<5, std::list>(test_list, 3),
1
)
);
return;
}
void remove_copy_if_test()
{
// std::remove_copy_if test cases
// std::vector<int>
std::vector<int> test_vector{ 5, 7, 4, 2, 8, 6, 1, 9, 0, 3 };
recursive_print(recursive_function_applier<0>(std::ranges::remove_copy_if, test_vector, std::bind(std::less<int>(), std::placeholders::_1, 5)));
// std::vector<std::vector<int>>
std::vector<decltype(test_vector)> test_vector2{ test_vector , test_vector , test_vector };
recursive_print(recursive_function_applier<1>(std::ranges::remove_copy_if, test_vector2, std::bind(std::less<int>(), std::placeholders::_1, 5)));
// std::vector<std::string>
std::vector<std::string> test_string_vector{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" };
recursive_print(
recursive_function_applier<0>(
std::ranges::remove_copy_if, test_string_vector, [](std::string x) { return (x == "0"); }
)
);
// std::vector<std::vector<std::string>>
std::vector<decltype(test_string_vector)> test_string_vector2{ test_string_vector , test_string_vector , test_string_vector };
recursive_print(
recursive_function_applier<1>(
std::ranges::remove_copy_if, test_string_vector2, [](std::string x) { return (x == "0"); }
)
);
// 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_function_applier<0>(std::ranges::remove_copy_if, test_deque, std::bind(std::less<int>(), std::placeholders::_1, 5)));
// 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_function_applier<1>(std::ranges::remove_copy_if, test_deque2, std::bind(std::less<int>(), std::placeholders::_1, 5)));
// std::list<int>
std::list<int> test_list = { 1, 2, 3, 4, 5, 6 };
recursive_print(recursive_function_applier<0>(std::ranges::remove_copy_if, test_list, std::bind(std::less<int>(), std::placeholders::_1, 5)));
// std::list<std::list<int>>
std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list };
recursive_print(recursive_function_applier<1>(std::ranges::remove_copy_if, test_list2, std::bind(std::less<int>(), std::placeholders::_1, 5)));
recursive_print(
recursive_function_applier<5>(
std::ranges::remove_copy_if,
n_dim_container_generator<5, std::list>(test_list, 3),
std::bind(std::less<int>(), std::placeholders::_1, 5)
)
);
return;
}
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A recursive_replace_if Template Function Implementation in C++,
A recursive_copy_if Template Function Implementation in C++,
A recursive_count_if Function For Various Type Arbitrary Nested Iterable Implementation in C++
What changes has been made in the code since last question?
I am trying to implement a
recursive_function_applier
template function as a function applier for applying various algorithms on nested container.Why a new review is being asked for?
Not sure the design of
recursive_function_applier
template function is a good idea or not. Whatever, this structure seems to be working fine instd::ranges::copy
,std::ranges::replace_copy_if
,std::ranges::remove_copy
andstd::ranges::remove_copy_if
cases. If there is any possible improvement, please let me know.