This is the follow-up question for A Summation Function For Various Type Arbitrary Nested Iterable Implementation in C++ and A Maximum Function For Various Type Arbitrary Nested Iterable Implementation in C++. In the summation and the maximum cases, the recursive technique is used for iterating all elements. The similar recursive structure is also used here. As the title mentioned, I am trying to implement a TransformAll
function which can apply a function to arbitrary nested ranges. I know there is a std::transform
function which can apply a function to a range and the applied range can be specified by first1, last1
parameters. I want to focus on the nested ranges here. The TransformAll
function is with two input parameters, one is input ranges, the other is operation function object. The operation function object would be applied to all elements in the input range then return the result. The main implementation is devided into two types. The first one type as follow is the single iterable case, such as std::vector<long double>{ 1, 1, 1 })
.
template<class T, class _Fn> requires Iterable<T>
static T TransformAll(const T _input, _Fn _Func); // Deal with the iterable case like "std::vector<long double>"
template<class T, class _Fn> requires Iterable<T>
static inline T TransformAll(const T _input, _Fn _Func)
{
T returnObject = _input;
std::transform(_input.begin(), _input.end(), returnObject.begin(), _Func);
return returnObject;
}
The second one is to deal with the nested iterable case like std::vector<std::vector<long double>>
.
template<class T, class _Fn> requires Iterable<T> && ElementIterable<T>
static T TransformAll(const T _input, _Fn _Func);
template<class T, class _Fn> requires Iterable<T> && ElementIterable<T>
static inline T TransformAll(const T _input, _Fn _Func)
{
T returnObject = _input;
std::transform(_input.begin(), _input.end(), returnObject.begin(),
[_Func](auto element)->auto
{
return TransformAll(element, _Func);
}
);
return returnObject;
}
The usage of the TransformAll
:
std::vector<long double> testVector1;
testVector1.push_back(1);
testVector1.push_back(20);
testVector1.push_back(-100);
std::cout << TransformAll(testVector1, [](long double x)->long double { return x + 1; }).at(0) << std::endl;
std::vector<long double> testVector2;
testVector2.push_back(10);
testVector2.push_back(90);
testVector2.push_back(-30);
std::vector<std::vector<long double>> testVector3;
testVector3.push_back(testVector1);
testVector3.push_back(testVector2);
std::cout << TransformAll(testVector3, [](long double x)->long double { return x + 1; }).at(1).at(1) << std::endl;
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
A Summation Function For Various Type Arbitrary Nested Iterable Implementation in C++ and
A Maximum Function For Various Type Arbitrary Nested Iterable Implementation in C++.
What changes has been made in the code since last question?
The previous question focus on the summation and the maximum operation. The main idea in this question is trying to process all base elements in various nested ranges with a lambda function and remain the origin structure in output result.
Why a new review is being asked for?
I think the design of this
TransformAll
function is more complex than the previous summation function case and maximum function case. The return value of the summation function case and the maximum function case is a single value. For keeping the origin structure here, the return type in each recursion epoch may be different. In my opinion about this code, there might be some problems existed. In the nested iterable case, is it a good idea aboutT returnObject = _input;
? The size ofreturnObject
is must the same as_input
in order to work well withstd::transform
. Is there any better idea for allocate the size of thisreturnObject
?
Oct 23, 2020 Update
The used Iterable
and ElementIterable
concepts are here.
template<typename T>
concept Iterable = requires(T x)
{
x.begin(); // must have `x.begin()`
x.end(); // and `x.end()`
};
template<typename T>
concept ElementIterable = requires(T x)
{
x.begin()->begin();
x.end()->end();
};