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.