This is a follow-up question for A Sine Template Function For Boost.MultiArray in C++, A recursive_transform for std::array with various return type, A recursive_transform for std::vector with various return type and A recursive_transform Function For Various Type Nested Iterable With std::variant Implementation in C++.
In the previous question A Sine Template Function For Boost.MultiArray in C++, there is a suggestion which is to use recursive_transform
function to handle multi_array
s in G. Sliepen's answer. However, I found that the existed version of recursive_transform
couldn't handle multi_array
s well. In other words, another version of recursive_transform
function which can be capable of multi_array
structure is needed. I am trying to implement this as below. First, some concepts including is_multi_array
, is_sub_array
and is_const_sub_array
are created.
template<typename T>
concept is_multi_array = requires(T x)
{
x.num_dimensions();
x.shape();
boost::multi_array(x);
};
template<typename T>
concept is_sub_array = requires(T x)
{
x.num_dimensions();
x.shape();
boost::detail::multi_array::sub_array(x);
};
template<typename T>
concept is_const_sub_array = requires(T x)
{
x.num_dimensions();
x.shape();
boost::detail::multi_array::const_sub_array(x);
};
The main part of the recursive_transform
function:
template<class T, class F>
auto recursive_transform(const T& input, const F& f)
{
return f(input);
}
template<class T, std::size_t S, class F>
auto recursive_transform(const std::array<T, S>& input, const F& f)
{
using TransformedValueType = decltype(recursive_transform(*input.cbegin(), f));
std::array<TransformedValueType, S> output;
std::transform(input.cbegin(), input.cend(), output.begin(),
[f](auto& element)
{
return recursive_transform(element, f);
}
);
return output;
}
template<template<class...> class Container, class Function, class... Ts>
// non-recursive version
auto recursive_transform(const Container<Ts...>& input, const Function& f)
{
using TransformedValueType = decltype(f(*input.cbegin()));
Container<TransformedValueType> output;
std::transform(input.cbegin(), input.cend(), std::back_inserter(output), f);
return output;
}
template<template<class...> class Container, class Function, class... Ts>
requires is_elements_iterable<Container<Ts...>>
auto recursive_transform(const Container<Ts...>& input, const Function& f)
{
using TransformedValueType = decltype(recursive_transform(*input.cbegin(), f));
Container<TransformedValueType> output;
std::transform(input.cbegin(), input.cend(), std::back_inserter(output),
[&](auto& element)
{
return recursive_transform(element, f);
}
);
return output;
}
template<class T, class F> requires (is_multi_array<T> || is_sub_array<T> || is_const_sub_array<T>)
auto recursive_transform(const T& input, const F& f)
{
boost::multi_array output(input);
for (decltype(+input.shape()[0]) i = 0; i < input.shape()[0]; i++)
{
output[i] = recursive_transform(input[i], f);
}
return output;
}
Moreover, the used is_elements_iterable
concept:
template<typename T>
concept is_elements_iterable = requires(T x)
{
std::begin(x)->begin();
std::end(x)->end();
};
Finally, the test of this recursive_transform
with Boost.MultiArray is as follows.
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 1;
for (index i = 0; i != 3; ++i)
for (index j = 0; j != 4; ++j)
for (index k = 0; k != 2; ++k)
A[i][j][k] = values++;
for (index i = 0; i != 3; ++i)
for (index j = 0; j != 4; ++j)
for (index k = 0; k != 2; ++k)
std::cout << A[i][j][k] << std::endl;
auto test_result = recursive_transform(A, [](auto& x) {return std::sin(x); });
for (index i = 0; i != 3; ++i)
for (index j = 0; j != 4; ++j)
for (index k = 0; k != 2; ++k)
std::cout << test_result[i][j][k] << std::endl;
The whole test of this recursive_transform
can be checked at here.
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A Sine Template Function For Boost.MultiArray in C++,
A recursive_transform for std::array with various return type,
A recursive_transform for std::vector with various return type and
What changes has been made in the code since last question?
Improving the capability of
recursive_transform
function withmulti_array
structure.Why a new review is being asked for?
All suggestions about this
recursive_transform
function are welcome.