Skip to main content
Update full testing code
Source Link
JimmyHu
  • 7.6k
  • 2
  • 11
  • 48
//  A `recursive_reduce_string` Template Function Implementation in C++

#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <concepts>
#include <deque>
#include <execution>
#include <iostream>
#include <mutex>
#include <queue>
#include <ranges>
#include <string>
#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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
Play with std::vectors:
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Play with std::deque:
1234
123412341234
Computation finished at Tue Oct 17 0408:2331:1604 2023
elapsed time: 20.8577e-0500128089

Godbolt link is here.Godbolt link is here.

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

#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <concepts>
#include <deque>
#include <execution>
#include <iostream>
#include <mutex>
#include <queue>
#include <ranges>
#include <string>
#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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
Play with std::vectors:
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Play with std::deque:
1234
123412341234
Computation finished at Tue Oct 17 04:23:16 2023
elapsed time: 2.8577e-05

Godbolt link is here.

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

#include <algorithm>
#include <array>
#include <chrono>
#include <concepts>
#include <deque>
#include <execution>
#include <iostream>
#include <queue>
#include <ranges>
#include <string>
#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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
Play with std::vectors:
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Play with std::deque:
1234
123412341234
Computation finished at Tue Oct 17 08:31:04 2023
elapsed time: 0.00128089

Godbolt link is here.

Update full testing code
Source Link
JimmyHu
  • 7.6k
  • 2
  • 11
  • 48
//  A `recursive_reduce_string` 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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}

Godbolt link is here.Godbolt link is here.

//  A `recursive_reduce_string` 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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}

Godbolt link is here.

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

#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <concepts>
#include <deque>
#include <execution>
#include <iostream>
#include <mutex>
#include <queue>
#include <ranges>
#include <string>
#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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}

Godbolt link is here.

Update full testing code
Source Link
JimmyHu
  • 7.6k
  • 2
  • 11
  • 48
//  A `recursive_reduce_string` 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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

intvoid mainrecursive_reduce_string_tests()
{
    autostd::cout start<< ="Play with std::chrono::system_clock:vectors:now();\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
Play with std::vectors:
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Play with std::deque:
1234
123412341234
Computation finished at Tue Oct 17 0104:0723:3216 2023
elapsed time: 02.001313138577e-05

Godbolt link is here.Godbolt link is here.

//  A `recursive_reduce_string` 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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

int main()
{
    auto start = std::chrono::system_clock::now();
    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Computation finished at Tue Oct 17 01:07:32 2023
elapsed time: 0.00131313

Godbolt link is here.

//  A `recursive_reduce_string` 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);
};

//  has_arithmetic_operations concept
template<class T>
concept has_arithmetic_operations = requires(T input)
{
    std::plus<>{}(input, input);
    std::minus<>{}(input, input);
    std::multiplies<>{}(input, input);
    std::divides<>{}(input, input);
};

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

template<std::ranges::input_range Range>
constexpr std::size_t recursive_depth()
{
    return recursive_depth<std::ranges::range_value_t<Range>>() + std::size_t{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_array_invoke_result implementation
template<std::size_t, typename, typename, typename...>
struct recursive_array_invoke_result { };

template<   typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
struct recursive_array_invoke_result<1, F, Container<T, N>>
{
    using type = Container<
        std::invoke_result_t<F, std::ranges::range_value_t<Container<T, N>>>,
        N>;
};

template<   std::size_t unwrap_level,
            typename F, 
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_invoke_result<
                                    unwrap_level - 1,
                                    F,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_invoke_result<unwrap_level, F, Container<T, N>>
{
    using type = Container<
        typename recursive_array_invoke_result<
        unwrap_level - 1,
        F,
        std::ranges::range_value_t<Container<T, N>>
        >::type, N>;
};

template<   std::size_t unwrap_level,
            typename F,
            template<class, std::size_t> class Container,
            typename T,
            std::size_t N>
using recursive_array_invoke_result_t = typename recursive_array_invoke_result<unwrap_level, F, Container<T, N>>::type;

//  recursive_unwrap_type_t struct implementation, https://codereview.stackexchange.com/q/284610/231235
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;

//  recursive_array_unwrap_type struct implementation, https://stackoverflow.com/a/76347485/6667035
template<std::size_t, typename>
struct recursive_array_unwrap_type { };

template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
struct recursive_array_unwrap_type<1, Container<T, N>>
{
    using type = std::ranges::range_value_t<Container<T, N>>;
};

template<std::size_t unwrap_level, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (  std::ranges::input_range<Container<T, N>> &&
            requires { typename recursive_array_unwrap_type<
                                    unwrap_level - 1,
                                    std::ranges::range_value_t<Container<T, N>>>::type; })                //  The rest arguments are ranges
struct recursive_array_unwrap_type<unwrap_level, Container<T, N>>
{
    using type = typename recursive_array_unwrap_type<
        unwrap_level - 1,
        std::ranges::range_value_t<Container<T, N>>
        >::type;
};

template<std::size_t unwrap_level, class Container>
using recursive_array_unwrap_type_t = typename recursive_array_unwrap_type<unwrap_level, Container>::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,
                class Proj = std::identity>
    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, Proj proj = {} )
    {
        if constexpr (unwrap_level > 0)
        {
            auto output = clone_empty_container(input, f);
            if constexpr (is_reservable<decltype(output)> &&
                          is_sized<decltype(input)> &&
                          std::indirectly_writable<decltype(output),
                            std::indirect_result_t<F&, std::projected<std::ranges::iterator_t<T>, Proj>>>)
            {
                output.reserve(input.size());
                std::ranges::transform(
                    input,
                    std::ranges::begin(output),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            else
            {
                std::ranges::transform(
                    input,
                    std::inserter(output, std::ranges::end(output)),
                    [&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); },
                    proj
                );
            }
            return output;
        }
        else if constexpr(std::regular_invocable<F, T>)
        {
            return std::invoke(f, std::invoke(proj, 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)
    {
        recursive_array_invoke_result_t<unwrap_level, F, Container, T, N> output{};

        if constexpr (unwrap_level > 1)
        {
            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::ranges::begin(output),
                        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 (unwrap_level <= recursive_depth<T>()&&        //  handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
              !std::ranges::view<T>)
    constexpr auto recursive_transform(const T& input, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            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, std::copy_constructible 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 std::invoke(f, input);
        }
    }

    //  recursive_transform implementation (binary case, the version with unwrap_level)
    template<std::size_t unwrap_level = 1, class ExPo, std::ranges::input_range R1, std::ranges::input_range R2, std::copy_constructible F>
    constexpr auto recursive_transform(ExPo execution_policy, const R1& input1, const R2& input2, const F& f)
    {
        if constexpr (unwrap_level > 0)
        {
            recursive_variadic_invoke_result_t<unwrap_level, F, R1> output{};
            output.resize(input1.size());
            std::mutex mutex;
            std::transform(execution_policy, std::ranges::cbegin(input1), std::ranges::cend(input1), std::ranges::cbegin(input2), std::ranges::begin(output),
                [&](auto&& element1, auto&& element2)
                {
                    std::lock_guard lock(mutex);
                    return recursive_transform<unwrap_level - 1>(execution_policy, element1, element2, f);
                });
            return output;
        }
        else
        {
            return std::invoke(f, input1, input2);
        }
    }
}

/*  recursive_reduce_all template function performs operation on input container exhaustively
https://codereview.stackexchange.com/a/285831/231235
*/
template<typename T> // No constraint since we're not reducing anything here!
constexpr auto recursive_reduce_all(const T& input)
{
    return input;
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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));
}

//  overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input));
}

template<std::ranges::input_range T>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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));
}

//  recursive_reduce_all template function with execution policy, overload for std::array
template<class ExPo, template<class, std::size_t> class Container,
              typename T,
              std::size_t N>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
    return input1 + input2;
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(const Container<T, N>& input, TI init)
{
    return std::reduce(std::ranges::cbegin(input), std::ranges::cend(input), init);
}

template<std::ranges::input_range T, class TI>
requires (has_arithmetic_operations<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, has_arithmetic_operations T>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy and initial value, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1)
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<has_arithmetic_operations T, class BinaryOp>
requires (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 (has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with initial value and specified operation, overload for std::array
template<template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI,
              class BinaryOp>
requires (has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(const Container<T, N>& 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 (has_arithmetic_operations<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, has_arithmetic_operations T, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          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>> &&
          has_arithmetic_operations<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);
}

//  recursive_reduce_all template function with execution policy, initial value and specified operation, overload for std::array
template<class ExPo,
              template<class, std::size_t> class Container,
              typename T,
              std::size_t N,
              class TI, class BinaryOp>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
          has_arithmetic_operations<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>> &&
          std::same_as<recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>, TI> &&
          recursive_depth<Container<T, N>>() == 1 &&
          std::regular_invocable<
            BinaryOp,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>,
            recursive_array_unwrap_type_t<recursive_depth<Container<T, N>>(), Container<T, N>>>
          )
constexpr auto recursive_reduce_all(ExPo execution_policy, const Container<T, N>& 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>> &&
          has_arithmetic_operations<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<std::size_t wrapped_level = 0, class T>
constexpr auto get_wrapped_first_element(const T& input)
{
    if constexpr (wrapped_level > 0)
    {
        return get_wrapped_first_element<wrapped_level - 1>(input.at(0));
    }
    else
    {
        return input;
    }
}

//  recursive_reduce_string template function
template<class T>
requires(std::same_as<T, std::string>)
constexpr auto recursive_reduce_string(const T& input1)
{
    return input1;
}

template<std::ranges::input_range T>
requires (std::same_as<recursive_unwrap_type_t<recursive_depth<T>() - 1, T>, std::string> &&
          recursive_depth<T>() - 1 == 1)
constexpr auto recursive_reduce_string(const T& input)
{
    auto output = input.at(0);
    for(int i = 1; i < std::ranges::size(input); i++)
    {
        output+=input.at(i);
    }
    return output;
}

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

void recursive_reduce_string_tests()
{
    std::cout << "Play with std::vectors:\n";

    std::vector<std::string> word_vector1 = {"foo", "bar", "baz", "quux"};
    std::cout << recursive_reduce_string(word_vector1) << '\n';
    
    std::vector<std::vector<std::string>> word_vector2 = {word_vector1, word_vector1, word_vector1};
    std::cout << recursive_reduce_string(word_vector2) << '\n';

    std::cout << "Play with std::deque:\n";
    std::deque<std::string> word_deque1 = {"1", "2", "3", "4"};
    std::cout << recursive_reduce_string(word_deque1) << '\n';

    std::deque<std::deque<std::string>> word_deque2 = {word_deque1, word_deque1, word_deque1};
    std::cout << recursive_reduce_string(word_deque2) << '\n';

    return;
}

int main()
{
    auto start = std::chrono::system_clock::now();
    recursive_reduce_string_tests();
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
    std::cout << "Computation finished at " << std::ctime(&end_time) << "elapsed time: " << elapsed_seconds.count() << '\n';
    return 0;
}
Play with std::vectors:
foobarbazquux
foobarbazquuxfoobarbazquuxfoobarbazquux
Play with std::deque:
1234
123412341234
Computation finished at Tue Oct 17 04:23:16 2023
elapsed time: 2.8577e-05

Godbolt link is here.

Source Link
JimmyHu
  • 7.6k
  • 2
  • 11
  • 48
Loading