Reputation: 127
SUMMARY
I stumbled upon the implementation of std::transform
and I could not figure out why it works in the case where we transform a container in-place. In particular, I found this expression confusing *d_first++ = unary_op(*first1++);
.
CODE
Using the first implementation of std::transform
found here https://en.cppreference.com/w/cpp/algorithm/transform, I wrote this sample code:
#include <iostream>
template< class InputIt,
class OutputIt,
class UnaryOperation >
OutputIt transform( InputIt first1,
InputIt last1,
OutputIt d_first,
UnaryOperation unary_op )
{
while (first1 != last1) {
*d_first++ = unary_op(*first1++);
}
return d_first;
}
int main() {
int arr[5] {1,2,3,4,5};
transform(std::begin(arr),std::end(arr),
std::begin(arr),
[](auto i){return i*i;});
for (auto& elem : arr) std::cout << elem << std::endl;
return 0;
}
ATTEMPT FOR AN EXPLANATION
After doing some reading in the C++ standard, Cpp reference, and SO, I think I might be able to explain what happens in that confusing (for me) statement. Let's decompose this expression:
*d_first++ = unary_op(*first1++); // same as A = B;
B
, which is, unary_op(*first1++)
*first1++
which means *(first1++)
which means a) make a copy of the
dereferenced first1
and b) pass it to the function, then c) increment the iterator.first1
is multiplied by itself inside the unary_op
.B
is evaluated, time to deal with the assignment.B
to the dereferenced value of d_first
.d_first
iterator.This way, the two iterators are "on the same page", meaning at the same position of the arrays which they iterate.
QUESTIONS
My questions are:
A) Is the above explanation correct?
B) Which operations in that expression are evaluations and which computations?
C) Since *first1++
translates to *(first1++)
but the dereferencing happens before the incrementation, isn't that confusing to remember? However, (*first1)++
would mean something totally different, i.e. dereference first1
and pass it to the function and then increment this value by one; not the iterator! Any hints to remember how to untangle myself in such expressions?
Upvotes: 1
Views: 139
Reputation: 13387
Just answering C).
Any hints to remember how to untangle myself in such expressions?
*i++
, *dst++ = do_something_with(*src++);
, etc., are well-established patterns in C++ and C. Therefore, the suggestion is:
If you mean *(first++)
, write it as *first++
, because it is the least surprising. (And get used to reading this expression the right way.)
If you mean (*first)++
, then write it as such. (You have no choice anyway.) The presence of the parentheses indicates immediately, that a meaning is intended that is different from *first++
.
Upvotes: 2