How can we use std::transform
, if we don't want to transform each element into one transformed element, but two?
The following pseudo code illustrates what I want to achieve
std::transform(a.cbegin(), a.cend(), std::back_inserter(b), [](T const& x) {
return f(x) and g(x);
});
Of course, I could invoke std::transform
two times, but that would be annoying. Maybe we need to provide a custom inserter. Any other option?
transform
is only for doing a one-to-one transformation. A custom inserter wouldn't help you anyway since transform
is implemented something like this:
while (first1 != last1) {
*d_first++ = unary_op(*first1++); // you have no way to write
// more than one element
}
return d_first;
You would actually have to write a custom iterator for a
to iterate over each element twice, and then keep state in your functor to know if you're on the f
state or the g
state. You can see how complicated this is getting.
Anything outside of simple 1-1 transformations, you should you just use a for
loop:
for (const auto& x : a) {
b.push_back(f(x));
b.push_back(g(x));
}
And even for simple 1-1 transformations, I think a simple range-for
expression wins too.
You could additionally write your own transform
that takes an arbitrary number of functors:
template <typename InIt, typename OutIt, typename... Functors>
void transform(InIt first, InIt last, OutIt d_first, Functors... fs)
{
while (first != last) {
apply(*first, d_first, fs...);
first++;
}
}
with;
template <typename In, typename OutIt>
void apply(const In&, OutIt ) { }
template <typename In, typename OutIt, typename F, typename... Functors>
void apply(const In& in, OutIt& out, F f, Functors... fs)
{
*out++ = f(in);
apply(in, out, fs...);
}
used as (example):
transform(a.begin(), a.end(), back_inserter(b), f, g);
Usually in such cases you can use standard algorithm std::accumulate
declared in header <numeric>
.
For example
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>
#include <type_traits>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> v;
v.reserve( 2 * std::extent<decltype( a )>::value );
std::accumulate( std::begin( a ), std::end( a ),
std::back_inserter( v ),
[]( auto it, auto x )
{
return *it++ = x * x, *it++ = x * x * x, it;
} );
auto it = v.begin();
for ( int x : a )
{
std::cout << x << '\t' << *it++ << '\t';
std::cout << *it++ << std::endl;
}
return 0;
}
The program output is
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With