Реализация шаблонной функции recursive_reduce_all на C++

Это дополнительный вопрос для реализации шаблонной функции recursive_sum с уровнем развертывания в C++ и реализации структуры recursive_unwrap_type_t в C++. Учитывая ответ Г. Слипена:

Сделайте его более общим

Суммирование — очень специфическая операция. Что, если вместо этого вы хотите вычислить произведение всех элементов? Или получить минимальное или максимальное значение? Вместо жесткого кодирования операции создайте recursive_reduce() это работает как std::reduce(). У вас все еще может быть сумма по умолчанию, если вы не укажете, какую операцию выполнять.

я пытаюсь реализовать recursive_reduce_all() шаблонная функция в C++, которая исчерпывающе выполняет операцию над входным контейнером. Тестовые случаи включают в себя:

  • Чистый recursive_reduce_all функциональный тест

  • recursive_reduce_all функциональный тест с политиками выполнения

  • recursive_reduce_all функциональный тест с начальным значением

  • recursive_reduce_all функциональный тест с политиками выполнения и начальным значением

  • recursive_reduce_all функциональный тест с начальным значением и заданной операцией

  • recursive_reduce_all функциональный тест с политиками выполнения, начальным значением и указанной операцией (в общем лямбда-выражении)

Экспериментальная реализация

  • recursive_reduce_all() реализация шаблонной функции

    /*  recursive_reduce_all template function performs operation on input container exhaustively
    */
    template<class T> requires is_summable<T>
    constexpr auto recursive_reduce_all(const T& input)
    {
        return input;
    }
    
    template<std::ranges::input_range T>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              recursive_depth<T>() == 1)
    constexpr auto recursive_reduce_all(const T& input)
    {
        return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
    }
    
    template<std::ranges::input_range T>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>>)
    constexpr auto recursive_reduce_all(const T& input)
    {
        auto result = recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(input, [](auto&& element){ return recursive_reduce_all(element); })
            );
        return result;
    }
    
    //  recursive_reduce_all template function with execution policy
    template<class ExPo, class T>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<T>)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
    {
        return input;
    }
    
    template<class ExPo, std::ranges::input_range T>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              recursive_depth<T>() == 1)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
    {
        return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input));
    }
    
    template<class ExPo, std::ranges::input_range T>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>>)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
    {
        auto result = recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(
                execution_policy,
                input,
                [&](auto&& element){ return recursive_reduce_all(execution_policy, element); }
                )
            );
        return result;
    }
    
    //  recursive_reduce_all template function with initial value
    template<class T> requires is_summable<T>
    constexpr auto recursive_reduce_all(const T& input1, const T& input2)
    {
        return input1 + input2;
    }
    
    template<std::ranges::input_range T, class TI>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              recursive_depth<T>() == 1)
    constexpr auto recursive_reduce_all(const T& input, TI init)
    {
        return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
    }
    
    template<std::ranges::input_range T, class TI>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI>)
    constexpr auto recursive_reduce_all(const T& input, TI init)
    {
        auto result = init + recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(
                input,
                [&](auto&& element){ return recursive_reduce_all(element); })
            );
        return result;
    }
    
    //  recursive_reduce_all template function with execution policy and initial value
    template<class ExPo, class T>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<T>)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input1, const T& input2)
    {
        return input1 + input2;
    }
    
    template<class ExPo, std::ranges::input_range T, class TI>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              recursive_depth<T>() == 1)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init)
    {
        return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), init);
    }
    
    template<class ExPo, std::ranges::input_range T, class TI>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI>)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init)
    {
        auto result = init + recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(
                execution_policy,
                input,
                [&](auto&& element){ return recursive_reduce_all(execution_policy, element); })
            );
        return result;
    }
    
    //  recursive_reduce_all template function with initial value and specified operation
    template<class T, class BinaryOp>
    requires (is_summable<T> &&
              std::regular_invocable<BinaryOp, T, T>)
    constexpr auto recursive_reduce_all(const T& input1, const T& input2, BinaryOp binary_op)
    {
        return std::invoke(binary_op, input1, input2);
    }
    
    template<std::ranges::input_range T, class TI, class BinaryOp>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              recursive_depth<T>() == 1 &&
              std::regular_invocable<
                BinaryOp,
                recursive_unwrap_type_t<recursive_depth<T>(),T>,
                recursive_unwrap_type_t<recursive_depth<T>(), T>>
              )
    constexpr auto recursive_reduce_all(const T& input, TI init, BinaryOp binary_op)
    {
        return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init, binary_op);
    }
    
    template<std::ranges::input_range T, class TI, class BinaryOp>
    requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              std::regular_invocable<
                BinaryOp,
                recursive_unwrap_type_t<recursive_depth<T>(),T>,
                recursive_unwrap_type_t<recursive_depth<T>(), T>>
              )
    constexpr auto recursive_reduce_all(const T& input, TI init, BinaryOp binary_op)
    {
        auto result = init + recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(
                input,
                [&](auto&& element){ return recursive_reduce_all(element, init, binary_op); })
            );
        return result;
    }
    
    //  recursive_reduce_all template function with execution policy, initial value and specified operation
    template<class ExPo, class T, class BinaryOp>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<T> &&
              std::regular_invocable<BinaryOp, T, T>)
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input1, const T& input2, BinaryOp binary_op)
    {
        return std::invoke(binary_op, input1, input2);
    }
    
    template<class ExPo, std::ranges::input_range T, class TI, class BinaryOp>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              recursive_depth<T>() == 1 &&
              std::regular_invocable<
                BinaryOp,
                recursive_unwrap_type_t<recursive_depth<T>(),T>,
                recursive_unwrap_type_t<recursive_depth<T>(), T>>
              )
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init, BinaryOp binary_op)
    {
        return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), init, binary_op);
    }
    
    template<class ExPo, std::ranges::input_range T, class TI, class BinaryOp>
    requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
              is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
              std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
              std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
              std::regular_invocable<
                BinaryOp,
                recursive_unwrap_type_t<recursive_depth<T>(),T>,
                recursive_unwrap_type_t<recursive_depth<T>(), T>>
              )
    constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init, BinaryOp binary_op)
    {
        auto result = init + recursive_reduce_all(
            UL::recursive_transform<recursive_depth<T>() - 1>(
                execution_policy,
                input,
                [&](auto&& element){ return recursive_reduce_all(execution_policy, element, init, binary_op); })
            );
        return result;
    }
    

Полный тестовый код

Полный тестовый код:

//  A `recursive_reduce_all` Template Function Implementation in C++

#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <complex>
#include <concepts>
#include <deque>
#include <execution>
#include <exception>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <mutex>
#include <numeric>
#include <optional>
#include <queue>
#include <ranges>
#include <stack>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>

//  is_reservable concept
template<class T>
concept is_reservable = requires(T input)
{
    input.reserve(1);
};

//  is_sized concept, https://codereview.stackexchange.com/a/283581/231235
template<class T>
concept is_sized = requires(T x)
{
    std::size(x);
};

template<typename T>
concept is_summable = requires(T x) { x + x; };

//  recursive_depth function implementation
template<typename T>
constexpr std::size_t recursive_depth()
{
    return 0;
}

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + 1;
}

//  recursive_variadic_invoke_result_t implementation
template<std::size_t, typename, typename, typename...>
struct recursive_variadic_invoke_result { };

template<typename F, class...Ts1, template<class...>class Container1, typename... Ts>
struct recursive_variadic_invoke_result<1, F, Container1<Ts1...>, Ts...>
{
    using type = Container1<std::invoke_result_t<F,
        std::ranges::range_value_t<Container1<Ts1...>>,
        std::ranges::range_value_t<Ts>...>>;
};

template<std::size_t unwrap_level, typename F, class...Ts1, template<class...>class Container1, typename... Ts>
requires (  std::ranges::input_range<Container1<Ts1...>> &&
            requires { typename recursive_variadic_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container1<Ts1...>>,
                                    std::ranges::range_value_t<Ts>...>::type; })                //  The rest arguments are ranges
struct recursive_variadic_invoke_result<unwrap_level, F, Container1<Ts1...>, Ts...>
{
    using type = Container1<
        typename recursive_variadic_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container1<Ts1...>>,
        std::ranges::range_value_t<Ts>...
        >::type>;
};

template<std::size_t unwrap_level, typename F, typename T1, typename... Ts>
using recursive_variadic_invoke_result_t = typename recursive_variadic_invoke_result<unwrap_level, F, T1, Ts...>::type;

//  recursive_unwrap_type_t struct implementation
template<std::size_t, typename, typename...>
struct recursive_unwrap_type { };

template<class...Ts1, template<class...>class Container1, typename... Ts>
struct recursive_unwrap_type<1, Container1<Ts1...>, Ts...>
{
    using type = std::ranges::range_value_t<Container1<Ts1...>>;
};

template<std::size_t unwrap_level, class...Ts1, template<class...>class Container1, typename... Ts>
requires (  std::ranges::input_range<Container1<Ts1...>> &&
            requires { typename recursive_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container1<Ts1...>>,
                                    std::ranges::range_value_t<Ts>...>::type; })                //  The rest arguments are ranges
struct recursive_unwrap_type<unwrap_level, Container1<Ts1...>, Ts...>
{
    using type = typename recursive_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container1<Ts1...>>
        >::type;
};

template<std::size_t unwrap_level, typename T1, typename... Ts>
using recursive_unwrap_type_t = typename recursive_unwrap_type<unwrap_level, T1, Ts...>::type;

//  https://codereview.stackexchange.com/a/253039/231235
template<template<class...> class Container = std::vector, std::size_t dim, 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<Container, dim - 1, T>(input, times));
    }
}

namespace UL                                                //   unwrap_level
{
    template< std::ranges::input_range Container,
              std::copy_constructible F>
    requires (std::ranges::view<Container>&&
              std::is_object_v<F>)
    constexpr auto make_view(const Container& input, const F& f) noexcept
    {
        return std::ranges::transform_view(
                input,
                [&f](const auto&& element) constexpr { return recursive_transform(element, f ); } );
    }

    /* Override make_view to catch dangling references.  A borrowed range is
    * safe from dangling..
    */
    template <std::ranges::input_range T>
    requires (!std::ranges::borrowed_range<T>)
    constexpr std::ranges::dangling make_view(T&&) noexcept
    {
        return std::ranges::dangling();
    }

    //  clone_empty_container template function implementation
    template< std::size_t unwrap_level = 1,
              std::ranges::input_range Container,
              std::copy_constructible F>
    requires (std::ranges::view<Container>&&
              std::is_object_v<F>)
    constexpr auto clone_empty_container(const Container& input, const F& f) noexcept
    {
        const auto view = make_view(input, f);
        recursive_variadic_invoke_result<unwrap_level, F, Container> output(std::span{input});
        return output;
    }
    
    //  recursive_transform template function implementation (the version with unwrap_level template parameter)
    template<   std::size_t unwrap_level = 1,
                class T,
                std::copy_constructible F>
    requires (unwrap_level <= recursive_depth<T>() &&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              std::ranges::view<T>&&
              std::is_object_v<F>)         
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)>&&
                          is_sized<decltype(input)>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, input);
        }
        else
        {
            static_assert(!std::regular_invocable<F, T>, "Uninvocable?");
        }
    }

    /* This overload of recursive_transform is to support std::array
    */
    template< std::size_t unwrap_level = 1,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              typename F >
    requires (std::ranges::input_range<Container<T, N>>)
    constexpr auto recursive_transform(const Container<T, N>& input, const F& f)
    {
        Container<recursive_variadic_invoke_result_t<unwrap_level, F, T>, N> output;

        std::ranges::transform(
                        input,
                        std::ranges::begin(output),
                        [&f](auto&& element){ return recursive_transform<unwrap_level - 1>(element, f); }
                    );

        return output;
    }

    //  recursive_transform function implementation (the version with unwrap_level, without using view)
    template<std::size_t unwrap_level = 1, class T, class F>
    requires (!std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            static_assert(unwrap_level <= recursive_depth<T>(),
                "unwrap level higher than recursion depth of input");   //  trying to handle incorrect unwrap levels more gracefully
            recursive_variadic_invoke_result_t<unwrap_level, F, T> output{};
            std::ranges::transform(
                input,                      //  passing a range to std::ranges::transform()
                std::inserter(output, std::ranges::end(output)),
                [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
            );
            return output;
        }
        else
        {
            return std::invoke(f, input);   //   use std::invoke()
        }
    }

    //  recursive_transform implementation (the version with unwrap_level, with execution policy)
    template<std::size_t unwrap_level = 1, class ExPo, class T, class F>
    requires (unwrap_level <= recursive_depth<T>() &&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
    constexpr auto recursive_transform(ExPo execution_policy, const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, T> output{};
            output.resize(input.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
                [&](auto&& element)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element, f);
                });
            return output;
        }
        else
        {
            return f(input);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
*/
template<class T> requires is_summable<T>
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          recursive_depth<T>() == 1)
constexpr auto recursive_reduce_all(const T& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>>)
constexpr auto recursive_reduce_all(const T& input)
{
    auto result = recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(input, [](auto&& element){ return recursive_reduce_all(element); })
        );
    return result;
}

//  recursive_reduce_all template function with execution policy
template<class ExPo, class T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<T>)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
{
    return input;
}

template<class ExPo, std::ranges::input_range T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          recursive_depth<T>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
{
    return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input));
}

template<class ExPo, std::ranges::input_range T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>>)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input)
{
    auto result = recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(
            execution_policy,
            input,
            [&](auto&& element){ return recursive_reduce_all(execution_policy, element); }
            )
        );
    return result;
}

//  recursive_reduce_all template function with initial value
template<class T> requires is_summable<T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          recursive_depth<T>() == 1)
constexpr auto recursive_reduce_all(const T& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI>)
constexpr auto recursive_reduce_all(const T& input, TI init)
{
    auto result = init + recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(
            input,
            [&](auto&& element){ return recursive_reduce_all(element); })
        );
    return result;
}

//  recursive_reduce_all template function with execution policy and initial value
template<class ExPo, class T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<T>)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input1, const T& input2)
{
    return input1 + input2;
}

template<class ExPo, std::ranges::input_range T, class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          recursive_depth<T>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init)
{
    return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<class ExPo, std::ranges::input_range T, class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI>)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init)
{
    auto result = init + recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(
            execution_policy,
            input,
            [&](auto&& element){ return recursive_reduce_all(execution_policy, element); })
        );
    return result;
}

//  recursive_reduce_all template function with initial value and specified operation
template<class T, class BinaryOp>
requires (is_summable<T> &&
          std::regular_invocable<BinaryOp, T, T>)
constexpr auto recursive_reduce_all(const T& input1, const T& input2, BinaryOp binary_op)
{
    return std::invoke(binary_op, input1, input2);
}

template<std::ranges::input_range T, class TI, class BinaryOp>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          recursive_depth<T>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_unwrap_type_t<recursive_depth<T>(),T>,
            recursive_unwrap_type_t<recursive_depth<T>(), T>>
          )
constexpr auto recursive_reduce_all(const T& input, TI init, BinaryOp binary_op)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init, binary_op);
}

template<std::ranges::input_range T, class TI, class BinaryOp>
requires (is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          std::regular_invocable<
            BinaryOp,
            recursive_unwrap_type_t<recursive_depth<T>(),T>,
            recursive_unwrap_type_t<recursive_depth<T>(), T>>
          )
constexpr auto recursive_reduce_all(const T& input, TI init, BinaryOp binary_op)
{
    auto result = init + recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(
            input,
            [&](auto&& element){ return recursive_reduce_all(element, init, binary_op); })
        );
    return result;
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation
template<class ExPo, class T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<T> &&
          std::regular_invocable<BinaryOp, T, T>)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input1, const T& input2, BinaryOp binary_op)
{
    return std::invoke(binary_op, input1, input2);
}

template<class ExPo, std::ranges::input_range T, class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          recursive_depth<T>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_unwrap_type_t<recursive_depth<T>(),T>,
            recursive_unwrap_type_t<recursive_depth<T>(), T>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init, BinaryOp binary_op)
{
    return std::reduce(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), init, binary_op);
}

template<class ExPo, std::ranges::input_range T, class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          is_summable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
          std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
          std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
          std::regular_invocable<
            BinaryOp,
            recursive_unwrap_type_t<recursive_depth<T>(),T>,
            recursive_unwrap_type_t<recursive_depth<T>(), T>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init, BinaryOp binary_op)
{
    auto result = init + recursive_reduce_all(
        UL::recursive_transform<recursive_depth<T>() - 1>(
            execution_policy,
            input,
            [&](auto&& element){ return recursive_reduce_all(execution_policy, element, init, binary_op); })
        );
    return result;
}

template<class T>
requires (std::ranges::input_range<T>)
constexpr auto recursive_print(const T& input, const int level = 0)
{
    T output = input;
    std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
    std::transform(input.cbegin(), input.cend(), output.begin(), 
        [level](auto&& x)
        {
            std::cout << std::string(level, ' ') << x << std::endl;
            return x;
        }
    );
    return output;
}

template<class T>
requires (std::ranges::input_range<T> &&
          std::ranges::input_range<std::ranges::range_value_t<T>>)
constexpr T recursive_print(const T& input, const int level = 0)
{
    T output = input;
    std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
    std::transform(input.cbegin(), input.cend(), output.begin(),
        [level](auto&& element)
        {
            return recursive_print(element, level + 1);
        }
    );
    return output;
}

void recursive_reduce_all_tests()
{
    auto test_vectors = n_dim_container_generator<std::vector, 4, double>(1, 4);
    
    std::cout << "Play with test_vectors:\n\n";

    std::cout << "recursive_reduce_all function test: \n";
    auto recursive_reduce_all_result1 = recursive_reduce_all(test_vectors);
    std::cout << recursive_reduce_all_result1 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq): \n";
    auto recursive_reduce_all_result2 = recursive_reduce_all(std::execution::seq, test_vectors);
    std::cout << recursive_reduce_all_result2 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par): \n";
    auto recursive_reduce_all_result3 = recursive_reduce_all(std::execution::par, test_vectors);
    std::cout << recursive_reduce_all_result3 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq): \n";
    auto recursive_reduce_all_result4 = recursive_reduce_all(std::execution::par_unseq, test_vectors);
    std::cout << recursive_reduce_all_result4 << "\n\n";
    
    std::cout << "recursive_reduce_all function test with initial value: \n";
    auto recursive_reduce_all_result5 = recursive_reduce_all(test_vectors, static_cast<double>(1));
    std::cout << recursive_reduce_all_result5 << "\n\n";
    
    std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq) and initial value: \n";
    auto recursive_reduce_all_result6 = recursive_reduce_all(std::execution::seq, test_vectors, static_cast<double>(1));
    std::cout << recursive_reduce_all_result6 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par) and initial value: \n";
    auto recursive_reduce_all_result7 = recursive_reduce_all(std::execution::par, test_vectors, static_cast<double>(1));
    std::cout << recursive_reduce_all_result7 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value: \n";
    auto recursive_reduce_all_result8 = recursive_reduce_all(std::execution::par_unseq, test_vectors, static_cast<double>(1));
    std::cout << recursive_reduce_all_result8 << "\n\n";
    
    std::cout << "recursive_reduce_all function test with initial value and specified operation: \n";
    auto recursive_reduce_all_result9 = recursive_reduce_all(test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
    std::cout << recursive_reduce_all_result9 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation: \n";
    auto recursive_reduce_all_result10 = recursive_reduce_all(std::execution::seq, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
    std::cout << recursive_reduce_all_result10 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation: \n";
    auto recursive_reduce_all_result11 = recursive_reduce_all(std::execution::par, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
    std::cout << recursive_reduce_all_result11 << "\n\n";

    std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation: \n";
    auto recursive_reduce_all_result12 = recursive_reduce_all(std::execution::par_unseq, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
    std::cout << recursive_reduce_all_result12 << "\n\n";
    
    return;
}

int main()
{
    recursive_reduce_all_tests();

    return 0;
}

Вывод тестового кода выше:

Play with test_vectors:

recursive_reduce_all function test: 
256

recursive_reduce_all function test with execution policy (std::execution::seq): 
256

recursive_reduce_all function test with execution policy (std::execution::par): 
256

recursive_reduce_all function test with execution policy (std::execution::par_unseq): 
256

recursive_reduce_all function test with initial value: 
257

recursive_reduce_all function test with execution policy (std::execution::seq) and initial value: 
257

recursive_reduce_all function test with execution policy (std::execution::par) and initial value: 
257

recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value: 
257

recursive_reduce_all function test with initial value and specified operation: 
65

recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation: 
65

recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation: 
65

recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation: 
65

Ссылка на Godbolt здесь.

Все предложения приветствуются.

Сводная информация:

  • Какой вопрос является продолжением?

    Реализация функции шаблона recursive_sum с уровнем развертывания на C++ и

    Реализация структуры recursive_unwrap_type_t на C++.

  • Какие изменения были внесены в код с момента последнего вопроса?

    я пытаюсь реализовать recursive_reduce_all() шаблонная функция в C++, которая исчерпывающе выполняет операцию над входным контейнером.

  • Почему запрашивается новый отзыв?

    Пожалуйста, ознакомьтесь с recursive_reduce_all() реализация функции шаблона и функция ее тестирования recursive_reduce_all_tests.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *