This is a follow-up question for [A population_variance Function For Various Type Arbitrary Nested Iterable Implementation in C++](https://codereview.stackexchange.com/q/253131/231235). Thanks to [G. Sliepen's answer](https://codereview.stackexchange.com/q/253131/231235), I am trying to implement the mentioned `recursive_transform_reduce` function here. **The usage description** Similar to [`std::transform_reduce`](https://en.cppreference.com/w/cpp/algorithm/transform_reduce), the purpose of `recursive_transform_reduce` function is to apply a function (unary operation) to each element in the given range then reduce the results with a binary operation. There are four parameters in `recursive_transform_reduce` function (the version without execution policy). The first one is a input range, the second one is the initial value of reduction result, the third one is a function (unary operation) which is to apply to each element and the final one is a binary operation for reduction operation. **The experimental implementation** The experimental implementation of `recursive_transform_reduce` template function is as below. ```C++ // recursive_transform_reduce implementation template<class Container, class ValueType, class UnaryOp, class BinaryOp = std::plus<ValueType>> requires (std::ranges::range<Container>) && (!is_elements_iterable<Container>) constexpr auto recursive_transform_reduce(const Container& input, ValueType init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<ValueType>()) { for (const auto& element : input) { auto result = unary_op(element); init = binop(init, result); } return init; } template<class Container, class ValueType, class UnaryOp, class BinaryOp = std::plus<ValueType>> requires (std::ranges::range<Container>) && (is_elements_iterable<Container>) constexpr auto recursive_transform_reduce(const Container& input, ValueType init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<ValueType>()) { return std::transform_reduce(std::begin(input), std::end(input), init, binop, [&](auto& element) { return recursive_transform_reduce(element, init, unary_op, binop); }); } // With execution policy template<class ExPo, class Container, class ValueType, class UnaryOp, class BinaryOp = std::plus<ValueType>> requires ((std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (std::ranges::range<Container>) && (!is_elements_iterable<Container>)) constexpr auto recursive_transform_reduce(ExPo execution_policy, const Container& input, ValueType init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<ValueType>()) { for (const auto& element : input) { auto result = unary_op(element); init = binop(init, result); } return init; } template<class ExPo, class Container, class ValueType, class UnaryOp, class BinaryOp = std::plus<ValueType>> requires ((std::is_execution_policy_v<std::remove_cvref_t<ExPo>>) && (std::ranges::range<Container>) && (is_elements_iterable<Container>)) constexpr auto recursive_transform_reduce(ExPo execution_policy, const Container& input, ValueType init, const UnaryOp& unary_op, const BinaryOp& binop = std::plus<ValueType>()) { return std::transform_reduce(execution_policy, std::begin(input), std::end(input), init, binop, [&](auto& element) { return recursive_transform_reduce(execution_policy, element, init, unary_op, binop); }); } ``` **Test cases** With `recursive_transform_reduce` function here, `population_variance` function in [the previous question](https://codereview.stackexchange.com/q/253131/231235) can be improved as below. ```C++ template<typename T> concept can_calculate_variance_of = requires(const T & value) { (std::pow(value, 2) - value) / std::size_t{ 1 }; }; template<typename T> struct recursive_iter_value_t_detail { using type = T; }; template <std::ranges::range T> struct recursive_iter_value_t_detail<T> : recursive_iter_value_t_detail<std::iter_value_t<T>> { }; template<typename T> using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type; // population_variance function implementation (with recursive_transform_reduce template function) template<class T = double, class Container> requires (is_recursive_sizeable<Container>&& can_calculate_variance_of<recursive_iter_value_t<Container>>) auto population_variance(const Container& input) { auto mean = arithmetic_mean<T>(input); return recursive_transform_reduce(std::execution::par, input, T{}, [mean](auto& element) { return std::pow(element - mean, 2); }, std::plus<T>()) / recursive_size(input); } ``` Note: `recursive_iter_value_t` is referred from [How to solve requires clause is incompatible](https://stackoverflow.com/a/65210724/6667035). The improved version of `arithmetic_mean` function implementation: ```C++ template<typename T> concept is_recursive_reduceable = requires(T x) { recursive_reduce(x, T{}); }; template<typename T> concept is_recursive_sizeable = requires(T x) { recursive_size(x); }; template<class T = double, class Container> requires (is_recursive_sizeable<Container>) auto arithmetic_mean(const Container& input) { return (recursive_reduce(input, T{})) / (recursive_size(input)); } ``` The `recursive_size` function implementation: ```C++ // recursive_size implementation template<class T> requires (!std::ranges::range<T>) auto recursive_size(const T& input) { return 1; } template<class T> requires (!is_elements_iterable<T> && std::ranges::range<T>) auto recursive_size(const T& input) { return input.size(); } template<class T> requires (is_elements_iterable<T>) auto recursive_size(const T& input) { return std::transform_reduce(std::begin(input), std::end(input), std::size_t{}, std::plus<std::size_t>(), [](auto& element) { return recursive_size(element); }); } ``` The test of `population_variance` function is like: ```C++ std::vector<double> test_vector{ 1, 2, 3, 4, 5 }; std::cout << "recursive_size of test_vector: " << recursive_size(test_vector) << std::endl; std::cout << "population_variance of test_vector: " << population_variance(test_vector) << std::endl; // std::vector<std::vector<double>> case std::vector<decltype(test_vector)> test_vector2; test_vector2.push_back(test_vector); test_vector2.push_back(test_vector); test_vector2.push_back(test_vector); std::cout << "recursive_size of test_vector2: " << recursive_size(test_vector2) << std::endl; std::cout << "population_variance of test_vector2: " << population_variance(test_vector2) << std::endl; auto test_vector3 = n_dim_container_generator<10, std::vector, decltype(test_vector)>(test_vector, 3); std::cout << "recursive_size of test_vector3: " << recursive_size(test_vector3) << std::endl; std::cout << "population_variance of test_vector3: " << population_variance(test_vector3) << std::endl; ``` Then, the execution output: ``` recursive_size of test_vector: 5 population_variance of test_vector: 2 recursive_size of test_vector2: 15 population_variance of test_vector2: 2 recursive_size of test_vector3: 295245 population_variance of test_vector3: 2 ``` Another test of `population_variance` function: ```C++ std::vector<double> test_vector{ 1, 2, 3 }; std::cout << "recursive_size of test_vector: " << recursive_size(test_vector) << std::endl; std::cout << "population_variance of test_vector: " << population_variance(test_vector) << std::endl; // std::vector<std::vector<double>> case std::vector<decltype(test_vector)> test_vector2; test_vector2.push_back(test_vector); test_vector2.push_back(test_vector); test_vector2.push_back(test_vector); std::cout << "recursive_size of test_vector2: " << recursive_size(test_vector2) << std::endl; std::cout << "population_variance of test_vector2: " << population_variance(test_vector2) << std::endl; auto test_vector3 = n_dim_container_generator<10, std::vector, decltype(test_vector)>(test_vector, 3); std::cout << "recursive_size of test_vector3: " << recursive_size(test_vector3) << std::endl; std::cout << "population_variance of test_vector3: " << population_variance(test_vector3) << std::endl; ``` The execution output of the above test code: ``` recursive_size of test_vector: 3 population_variance of test_vector: 0.666667 recursive_size of test_vector2: 9 population_variance of test_vector2: 0.666667 recursive_size of test_vector3: 177147 population_variance of test_vector3: 0.666667 ``` [A Godbolt link is here.](https://godbolt.org/z/86ohjd) All suggestions are welcome. The summary information: - Which question it is a follow-up to? [A population_variance Function For Various Type Arbitrary Nested Iterable Implementation in C++](https://codereview.stackexchange.com/q/253131/231235) - What changes has been made in the code since last question? I am trying to implement a recursive_transform_reduce function here and use it in `population_variance` function. - Why a new review is being asked for? Please check the implementation of `recursive_transform_reduce` function and if there is any possible improvement, please let me know.