This is a follow-up question for A recursive_transform for std::vector with various return type, A recursive_transform Function For Various Type Nested Iterable With std::variant Implementation in C++ and A recursive_transform for std::array with various return type. The execution policy parameter is available since C++17. I am trying to add this into the recursive_transform
template function. The experimental version code is as below.
// With execution policy
template<class ExPo, class T, class F>
auto recursive_transform(ExPo execution_policy, const T& input, const F& f)
{
return f(input);
}
template<class ExPo, class T, std::size_t S, class F>
requires std::is_execution_policy_v<std::remove_cvref_t<ExPo>>
auto recursive_transform(ExPo execution_policy, const std::array<T, S>& input, const F& f)
{
using TransformedValueType = decltype(recursive_transform(*input.cbegin(), f));
std::array<TransformedValueType, S> output;
std::transform(execution_policy, input.cbegin(), input.cend(), output.begin(),
[execution_policy, f](auto& element)
{
return recursive_transform(execution_policy, element, f);
}
);
return output;
}
template<class ExPo, template<class...> class Container, class Function, class... Ts>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> && is_iterable<Container<Ts...>> && !is_elements_iterable<Container<Ts...>>)
// non-recursive version
auto recursive_transform(ExPo execution_policy, const Container<Ts...>& input, const Function& f)
{
using TransformedValueType = decltype(f(*input.cbegin()));
Container<TransformedValueType> output(input.size());
std::transform(execution_policy, input.cbegin(), input.cend(), output.begin(), f);
return output;
}
template<class ExPo, template<class...> class Container, class Function, class... Ts>
requires (std::is_execution_policy_v<std::remove_cvref_t<ExPo>> && is_elements_iterable<Container<Ts...>>)
auto recursive_transform(ExPo execution_policy, const Container<Ts...>& input, const Function& f)
{
using TransformedValueType = decltype(recursive_transform(*input.cbegin(), f));
Container<TransformedValueType> output(input.size());
std::transform(execution_policy, input.cbegin(), input.cend(), output.begin(),
[&](auto& element)
{
return recursive_transform(execution_policy, element, f);
}
);
return output;
}
I found that std::back_inserter(output)
cannot be used in here due to the error happened Parallel algorithms require forward iterators or stronger.
Instead of using std::back_inserter()
to fill the containers, the .size()
function is used for constructing container. If there is any better way to handle the output container size, please let me know.
The test of this version of recursive_transform
template function:
// std::vector<int> -> std::vector<std::string>
std::vector<int> test_vector = {
1, 2, 3
};
auto recursive_transform_result = recursive_transform(
std::execution::par,
test_vector,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result.at(0) << std::endl; // recursive_transform_result.at(0) is a std::string
// std::vector<std::vector<int>> -> std::vector<std::vector<std::string>>
std::vector<decltype(test_vector)> test_vector2 = {
test_vector, test_vector, test_vector
};
auto recursive_transform_result2 = recursive_transform(
std::execution::par,
test_vector2,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result2.at(0).at(0) << std::endl; // recursive_transform_result.at(0).at(0) is also a std::string
// std::deque<int> -> std::deque<std::string>
std::deque<int> test_deque;
test_deque.push_back(1);
test_deque.push_back(1);
test_deque.push_back(1);
auto recursive_transform_result3 = recursive_transform(
std::execution::par,
test_deque,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result3.at(0) << std::endl;
// std::deque<std::deque<int>> -> std::deque<std::deque<std::string>>
std::deque<decltype(test_deque)> test_deque2;
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
test_deque2.push_back(test_deque);
auto recursive_transform_result4 = recursive_transform(
std::execution::par,
test_deque2,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result4.at(0).at(0) << std::endl;
// std::array<int, 10> -> std::array<std::string, 10>
std::array<int, 10> test_array;
for (int i = 0; i < 10; i++)
{
test_array[i] = 1;
}
auto recursive_transform_result5 = recursive_transform(
std::execution::par,
test_array,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result5.at(0) << std::endl;
// std::array<std::array<int, 10>, 10> -> std::array<std::array<std::string, 10>, 10>
std::array<std::array<int, 10>, 10> test_array2;
for (int i = 0; i < 10; i++)
{
test_array2[i] = test_array;
}
auto recursive_transform_result6 = recursive_transform(
std::execution::par,
test_array2,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result6.at(0).at(0) << std::endl;
// std::list<int> -> std::list<std::string>
std::list<int> test_list = { 1, 2, 3, 4 };
auto recursive_transform_result7 = recursive_transform(
std::execution::par,
test_list,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result7.front() << std::endl;
// std::list<std::list<int>> -> std::list<std::list<std::string>>
std::list<std::list<int>> test_list2 = { test_list, test_list, test_list, test_list };
auto recursive_transform_result8 = recursive_transform(
std::execution::par,
test_list2,
[](int x)->std::string { return std::to_string(x); }); // For testing
std::cout << "string: " + recursive_transform_result8.front().front() << std::endl;
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A recursive_transform for std::vector with various return type,
A recursive_transform for std::array with various return type
What changes has been made in the code since last question?
The execution policy parameter is considered here in this version of
recursive_transform
template function.Why a new review is being asked for?
In my opinion, I am not sure if it is a good idea to add the execution policy parameter in the above way. Especially the usage of
std::is_execution_policy_v<std::remove_cvref_t<ExPo>>
in constraint expression.