This is a follow-up question for A recursive_reduce_all
Template Function Implementation in C++. As G. Sliepen's answer mentioned:
std::is_arithmetic_v<>
checks whether the type is basically an integer or a float, nothing else will match.
I am trying to implement an arithmeticable
concept which checks whether the operations plus
, minus
,multiplies
and divides
are supported by given type.
The experimental implementation
arithmeticable
Concept Implementation// arithmeticable concept template<class T> concept arithmeticable = requires(T input) { std::plus<>{}(input, input); std::minus<>{}(input, input); std::multiplies<>{}(input, input); std::divides<>{}(input, input); };
Full Testing Code
The full testing code:
// An arithmeticable Concept 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>
// arithmeticable concept
template<class T>
concept arithmeticable = requires(T input)
{
std::plus<>{}(input, input);
std::minus<>{}(input, input);
std::multiplies<>{}(input, input);
std::divides<>{}(input, input);
};
// 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);
};
// 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>>() + 1;
}
// recursive_variadic_invoke_result_t implementation
template<std::size_t, typename, typename, typename...>
struct recursive_variadic_invoke_result { };
template<typename F, class...Ts1, template<class...>class Container1, typename... Ts>
struct recursive_variadic_invoke_result<1, F, Container1<Ts1...>, Ts...>
{
using type = Container1<std::invoke_result_t<F,
std::ranges::range_value_t<Container1<Ts1...>>,
std::ranges::range_value_t<Ts>...>>;
};
template<std::size_t unwrap_level, typename F, class...Ts1, template<class...>class Container1, typename... Ts>
requires ( std::ranges::input_range<Container1<Ts1...>> &&
requires { typename recursive_variadic_invoke_result<
unwrap_level - 1,
F,
std::ranges::range_value_t<Container1<Ts1...>>,
std::ranges::range_value_t<Ts>...>::type; }) // The rest arguments are ranges
struct recursive_variadic_invoke_result<unwrap_level, F, Container1<Ts1...>, Ts...>
{
using type = Container1<
typename recursive_variadic_invoke_result<
unwrap_level - 1,
F,
std::ranges::range_value_t<Container1<Ts1...>>,
std::ranges::range_value_t<Ts>...
>::type>;
};
template<std::size_t unwrap_level, typename F, typename T1, typename... Ts>
using recursive_variadic_invoke_result_t = typename recursive_variadic_invoke_result<unwrap_level, F, T1, Ts...>::type;
// recursive_unwrap_type_t struct implementation
template<std::size_t, typename, typename...>
struct recursive_unwrap_type { };
template<class...Ts1, template<class...>class Container1, typename... Ts>
struct recursive_unwrap_type<1, Container1<Ts1...>, Ts...>
{
using type = std::ranges::range_value_t<Container1<Ts1...>>;
};
template<std::size_t unwrap_level, class...Ts1, template<class...>class Container1, typename... Ts>
requires ( std::ranges::input_range<Container1<Ts1...>> &&
requires { typename recursive_unwrap_type<
unwrap_level - 1,
std::ranges::range_value_t<Container1<Ts1...>>,
std::ranges::range_value_t<Ts>...>::type; }) // The rest arguments are ranges
struct recursive_unwrap_type<unwrap_level, Container1<Ts1...>, Ts...>
{
using type = typename recursive_unwrap_type<
unwrap_level - 1,
std::ranges::range_value_t<Container1<Ts1...>>
>::type;
};
template<std::size_t unwrap_level, typename T1, typename... Ts>
using recursive_unwrap_type_t = typename recursive_unwrap_type<unwrap_level, T1, Ts...>::type;
// 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>
requires (unwrap_level <= recursive_depth<T>() && // handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
std::ranges::view<T>&&
std::is_object_v<F>)
constexpr auto recursive_transform(const T& input, const F& f)
{
if constexpr (unwrap_level > 0)
{
auto output = clone_empty_container(input, f);
if constexpr (is_reservable<decltype(output)>&&
is_sized<decltype(input)>)
{
output.reserve(input.size());
std::ranges::transform(
input,
std::ranges::begin(output),
[&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
);
}
else
{
std::ranges::transform(
input,
std::inserter(output, std::ranges::end(output)),
[&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
);
}
return output;
}
else if constexpr(std::regular_invocable<F, T>)
{
return std::invoke(f, input);
}
else
{
static_assert(!std::regular_invocable<F, T>, "Uninvocable?");
}
}
/* This overload of recursive_transform is to support std::array
*/
template< std::size_t unwrap_level = 1,
template<class, std::size_t> class Container,
typename T,
std::size_t N,
typename F >
requires (std::ranges::input_range<Container<T, N>>)
constexpr auto recursive_transform(const Container<T, N>& input, const F& f)
{
Container<recursive_variadic_invoke_result_t<unwrap_level, F, T>, N> output;
std::ranges::transform(
input,
std::ranges::begin(output),
[&f](auto&& element){ return recursive_transform<unwrap_level - 1>(element, f); }
);
return output;
}
// recursive_transform function implementation (the version with unwrap_level, without using view)
template<std::size_t unwrap_level = 1, class T, class F>
requires (!std::ranges::view<T>)
constexpr auto recursive_transform(const T& input, const F& f)
{
if constexpr (unwrap_level > 0)
{
static_assert(unwrap_level <= recursive_depth<T>(),
"unwrap level higher than recursion depth of input"); // trying to handle incorrect unwrap levels more gracefully
recursive_variadic_invoke_result_t<unwrap_level, F, T> output{};
std::ranges::transform(
input, // passing a range to std::ranges::transform()
std::inserter(output, std::ranges::end(output)),
[&f](auto&& element) { return recursive_transform<unwrap_level - 1>(element, f); }
);
return output;
}
else
{
return std::invoke(f, input); // use std::invoke()
}
}
// recursive_transform implementation (the version with unwrap_level, with execution policy)
template<std::size_t unwrap_level = 1, class ExPo, class T, class F>
requires (unwrap_level <= recursive_depth<T>() && // handling incorrect unwrap levels more gracefully, https://codereview.stackexchange.com/a/283563/231235
std::is_execution_policy_v<std::remove_cvref_t<ExPo>>)
constexpr auto recursive_transform(ExPo execution_policy, const T& input, const F& f)
{
if constexpr (unwrap_level > 0)
{
recursive_variadic_invoke_result_t<unwrap_level, F, T> output{};
output.resize(input.size());
std::mutex mutex;
std::transform(execution_policy, std::ranges::cbegin(input), std::ranges::cend(input), std::ranges::begin(output),
[&](auto&& element)
{
std::lock_guard lock(mutex);
return recursive_transform<unwrap_level - 1>(execution_policy, element, f);
});
return output;
}
else
{
return f(input);
}
}
}
/* recursive_reduce_all template function performs operation on input container exhaustively
*/
template<typename T>
constexpr auto recursive_reduce_all(const T& input)
{
return input;
}
template<std::ranges::input_range T>
requires (arithmeticable<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 (arithmeticable<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 (arithmeticable<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, arithmeticable 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>> &&
arithmeticable<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>> &&
arithmeticable<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>> &&
arithmeticable<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<arithmeticable T>
constexpr auto recursive_reduce_all(const T& input1, const T& input2)
{
return std::plus<>{}(input1, input2);
}
template<std::ranges::input_range T, class TI>
requires (arithmeticable<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 (arithmeticable<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 (arithmeticable<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 = std::plus<>{}(
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, arithmeticable 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 std::plus<>{}(input1, input2);
}
template<class ExPo, std::ranges::input_range T, class TI>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> &&
arithmeticable<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>> &&
arithmeticable<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>> &&
arithmeticable<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<arithmeticable 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 (arithmeticable<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 (arithmeticable<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 (arithmeticable<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, arithmeticable 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>> &&
arithmeticable<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>> &&
arithmeticable<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>> &&
arithmeticable<recursive_unwrap_type_t<recursive_depth<T>(), T>> &&
std::ranges::input_range<recursive_unwrap_type_t<1, T>> &&
std::same_as<recursive_unwrap_type_t<recursive_depth<T>(), T>, TI> &&
std::regular_invocable<
BinaryOp,
recursive_unwrap_type_t<recursive_depth<T>(),T>,
recursive_unwrap_type_t<recursive_depth<T>(), T>>
)
constexpr auto recursive_reduce_all(ExPo execution_policy, const T& input, TI init, BinaryOp binary_op)
{
auto result = init + recursive_reduce_all(
UL::recursive_transform<recursive_depth<T>() - 1>(
execution_policy,
input,
[&](auto&& element){ return recursive_reduce_all(execution_policy, element, init, binary_op); })
);
return result;
}
template<class T>
requires (std::ranges::input_range<T>)
constexpr auto recursive_print(const T& input, const int level = 0)
{
T output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::transform(input.cbegin(), input.cend(), output.begin(),
[level](auto&& x)
{
std::cout << std::string(level, ' ') << x << std::endl;
return x;
}
);
return output;
}
template<class T>
requires (std::ranges::input_range<T> &&
std::ranges::input_range<std::ranges::range_value_t<T>>)
constexpr T recursive_print(const T& input, const int level = 0)
{
T output = input;
std::cout << std::string(level, ' ') << "Level " << level << ":" << std::endl;
std::transform(input.cbegin(), input.cend(), output.begin(),
[level](auto&& element)
{
return recursive_print(element, level + 1);
}
);
return output;
}
void recursive_reduce_all_tests_vector()
{
auto test_vectors = n_dim_container_generator<std::vector, 4, double>(1, 4);
std::cout << "Play with test_vectors:\n\n";
std::cout << "Pure recursive_reduce_all function test: \n";
auto recursive_reduce_all_result1 = recursive_reduce_all(test_vectors);
std::cout << recursive_reduce_all_result1 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq): \n";
auto recursive_reduce_all_result2 = recursive_reduce_all(std::execution::seq, test_vectors);
std::cout << recursive_reduce_all_result2 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par): \n";
auto recursive_reduce_all_result3 = recursive_reduce_all(std::execution::par, test_vectors);
std::cout << recursive_reduce_all_result3 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq): \n";
auto recursive_reduce_all_result4 = recursive_reduce_all(std::execution::par_unseq, test_vectors);
std::cout << recursive_reduce_all_result4 << "\n\n";
std::cout << "recursive_reduce_all function test with initial value: \n";
auto recursive_reduce_all_result5 = recursive_reduce_all(test_vectors, static_cast<double>(1));
std::cout << recursive_reduce_all_result5 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq) and initial value: \n";
auto recursive_reduce_all_result6 = recursive_reduce_all(std::execution::seq, test_vectors, static_cast<double>(1));
std::cout << recursive_reduce_all_result6 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par) and initial value: \n";
auto recursive_reduce_all_result7 = recursive_reduce_all(std::execution::par, test_vectors, static_cast<double>(1));
std::cout << recursive_reduce_all_result7 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value: \n";
auto recursive_reduce_all_result8 = recursive_reduce_all(std::execution::par_unseq, test_vectors, static_cast<double>(1));
std::cout << recursive_reduce_all_result8 << "\n\n";
std::cout << "recursive_reduce_all function test with initial value and specified operation: \n";
auto recursive_reduce_all_result9 = recursive_reduce_all(test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result9 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation: \n";
auto recursive_reduce_all_result10 = recursive_reduce_all(std::execution::seq, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result10 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation: \n";
auto recursive_reduce_all_result11 = recursive_reduce_all(std::execution::par, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result11 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation: \n";
auto recursive_reduce_all_result12 = recursive_reduce_all(std::execution::par_unseq, test_vectors, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result12 << "\n\n";
return;
}
void recursive_reduce_all_tests_array()
{
auto test_array = std::array<double, 4>{1, 1, 1, 1};
std::cout << "Play with test_array:\n\n";
std::cout << "Pure recursive_reduce_all function test: \n";
auto recursive_reduce_all_result1 = recursive_reduce_all(test_array);
std::cout << recursive_reduce_all_result1 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq): \n";
auto recursive_reduce_all_result2 = recursive_reduce_all(std::execution::seq, test_array);
std::cout << recursive_reduce_all_result2 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par): \n";
auto recursive_reduce_all_result3 = recursive_reduce_all(std::execution::par, test_array);
std::cout << recursive_reduce_all_result3 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq): \n";
auto recursive_reduce_all_result4 = recursive_reduce_all(std::execution::par_unseq, test_array);
std::cout << recursive_reduce_all_result4 << "\n\n";
std::cout << "recursive_reduce_all function test with initial value: \n";
auto recursive_reduce_all_result5 = recursive_reduce_all(test_array, static_cast<double>(1));
std::cout << recursive_reduce_all_result5 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq) and initial value: \n";
auto recursive_reduce_all_result6 = recursive_reduce_all(std::execution::seq, test_array, static_cast<double>(1));
std::cout << recursive_reduce_all_result6 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par) and initial value: \n";
auto recursive_reduce_all_result7 = recursive_reduce_all(std::execution::par, test_array, static_cast<double>(1));
std::cout << recursive_reduce_all_result7 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value: \n";
auto recursive_reduce_all_result8 = recursive_reduce_all(std::execution::par_unseq, test_array, static_cast<double>(1));
std::cout << recursive_reduce_all_result8 << "\n\n";
std::cout << "recursive_reduce_all function test with initial value and specified operation: \n";
auto recursive_reduce_all_result9 = recursive_reduce_all(test_array, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result9 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation: \n";
auto recursive_reduce_all_result10 = recursive_reduce_all(std::execution::seq, test_array, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result10 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation: \n";
auto recursive_reduce_all_result11 = recursive_reduce_all(std::execution::par, test_array, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result11 << "\n\n";
std::cout << "recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation: \n";
auto recursive_reduce_all_result12 = recursive_reduce_all(std::execution::par_unseq, test_array, static_cast<double>(1), [](auto&& input1, auto&& input2) { return input1 * input2; });
std::cout << recursive_reduce_all_result12 << "\n\n";
return;
}
int main()
{
auto start = std::chrono::system_clock::now();
recursive_reduce_all_tests_vector();
recursive_reduce_all_tests_array();
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;
}
The output of the test code above:
Play with test_vectors:
Pure recursive_reduce_all function test:
256
recursive_reduce_all function test with execution policy (std::execution::seq):
256
recursive_reduce_all function test with execution policy (std::execution::par):
256
recursive_reduce_all function test with execution policy (std::execution::par_unseq):
256
recursive_reduce_all function test with initial value:
257
recursive_reduce_all function test with execution policy (std::execution::seq) and initial value:
257
recursive_reduce_all function test with execution policy (std::execution::par) and initial value:
257
recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value:
257
recursive_reduce_all function test with initial value and specified operation:
65
recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation:
65
recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation:
65
recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation:
65
Play with test_array:
Pure recursive_reduce_all function test:
4
recursive_reduce_all function test with execution policy (std::execution::seq):
4
recursive_reduce_all function test with execution policy (std::execution::par):
4
recursive_reduce_all function test with execution policy (std::execution::par_unseq):
4
recursive_reduce_all function test with initial value:
5
recursive_reduce_all function test with execution policy (std::execution::seq) and initial value:
5
recursive_reduce_all function test with execution policy (std::execution::par) and initial value:
5
recursive_reduce_all function test with execution policy (std::execution::par_unseq) and initial value:
5
recursive_reduce_all function test with initial value and specified operation:
1
recursive_reduce_all function test with execution policy (std::execution::seq), initial value and specified operation:
1
recursive_reduce_all function test with execution policy (std::execution::par), initial value and specified operation:
1
recursive_reduce_all function test with execution policy (std::execution::par_unseq), initial value and specified operation:
1
Computation finished at Sun Jul 9 17:26:04 2023
elapsed time: 0.00140964
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A
recursive_reduce_all
Template Function Implementation in C++.What changes has been made in the code since last question?
I am trying to implement an
arithmeticable
concept in this post.Why a new review is being asked for?
Please review the revised code and all suggestions are welcome.