for_each with vector of function objects

A

alan.patterson5

I have a vector of N values and a vector of N functors. I want to apply
each functor to its corresponding value. What would be the 'correct'
STL way to do this.
for_each takes on functor and applies it to every element.
So presumably transform is a better option but it also takes one
functor.
This is obviously easily solved by a variety of methods but I am
interested in how the STL would best solve this problem.
e.g.

// fill vector with some values
vector<int> x (values.begin(), values.end());

vector<functor> funcs;
// fill funcs with different functors, or functors with different
parameters

// would like to do STL equivalent of
for (int i=0; i<x.size(); ++i) {
funcs(x);
}
 
P

Pete Becker

I have a vector of N values and a vector of N functors. I want to apply
each functor to its corresponding value. What would be the 'correct'
STL way to do this.
for_each takes on functor and applies it to every element.
So presumably transform is a better option but it also takes one
functor.
This is obviously easily solved by a variety of methods but I am
interested in how the STL would best solve this problem.
e.g.

// fill vector with some values
vector<int> x (values.begin(), values.end());

vector<functor> funcs;
// fill funcs with different functors, or functors with different
parameters

// would like to do STL equivalent of
for (int i=0; i<x.size(); ++i) {
funcs(x);
}


I'd write the explicit loop. But if you want to write a template that
takes iterators, it would be something like this:

template <class Iter1, class Iter2>
void apply(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
{
while (first1 != last1 && first2 != last2)
(*first1++)(*first2++);
}

and you'd call it like this:

apply(funcs.begin(), funcs.end(), x.begin(), x.end());

Or, if the only reason you copied values in the first place was to get
the contents into a vector, you can skip that copy and pass the values
iterators:

apply(funcs.begin(), funcs.end(), values.begin(), values.end());

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
D

Daniel T.

I have a vector of N values and a vector of N functors. I want to apply
each functor to its corresponding value. What would be the 'correct'
STL way to do this.
for_each takes on functor and applies it to every element.
So presumably transform is a better option but it also takes one
functor.
This is obviously easily solved by a variety of methods but I am
interested in how the STL would best solve this problem.
e.g.

// fill vector with some values
vector<int> x (values.begin(), values.end());

vector<functor> funcs;
// fill funcs with different functors, or functors with different
parameters

// would like to do STL equivalent of
for (int i=0; i<x.size(); ++i) {
funcs(x);
}


There is a transform that takes iterators into two containers, but it
assumes that the functions will produce outputs and you don't seem to be
doing that. As such, I agree with Pete's post.
 
E

Earl Purple

Pete said:
I'd write the explicit loop. But if you want to write a template that
takes iterators, it would be something like this:

template <class Iter1, class Iter2>
void apply(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
{
while (first1 != last1 && first2 != last2)
(*first1++)(*first2++);
}

Do you need to increment both? transform that takes 2 inputs only
increments one and relies on "UB" if the unchecked sequence is shorter
than the first. (It can be longer, it simply runs for the length of the
checked sequence).

Also although it can be written in one line, I think it's better to use
pre-increment because it avoids a copy of the iterator, and you don't
know how expensive that might be from a template. Although it is more
lines in your code, I don't see that it will generate more lines of
object code. So how about:

template< typename Iter1, typename Iter2 >
void apply( Iter1 first1, Iter1 last1, Iter2 first2 )
{
while ( first1 != last1 )
{
(*first1)(*first2);
++first1;
++first2;
}
}
and you'd call it like this:

apply(funcs.begin(), funcs.end(), x.begin(), x.end());

In my example no x.end(), just the first 3 parameters.
 
E

Earl Purple

Daniel said:
There is a transform that takes iterators into two containers, but it
assumes that the functions will produce outputs and you don't seem to be
doing that. As such, I agree with Pete's post.

To use that you'd have to write a non-iterator for the output, and the
operator that takes the 2 parameters would get the functor to invoke on
the object. Easier to write the algorithm, but if we really want to use
transform:

iterator: all of the operators (++, *, =) will do nothing. operator=()
could be a template because it does nothing with its parameter anyway.
Not sure what you'd do with the typedefs if we really need them anyway.

operator:

struct call_func
{
template < typename F, typename P >
void operator() ( F func, P param )
{
func( param );
}
};

The final way is to use for_each and get the functor to store the
beginning of one sequence. Let's say it stores the functors. Again it
could store an iterator.

template < typename FuncIterator >
struct FunctorFunctor
{
private:
FuncIterator func_iter;

public:
explicit FunctorFunctor( FuncIterator fi ) : func_iter ( fi ) {}

template < typename T >
void operator() ( T t )
{
(*func_iter)( t );
++func_iter;
}
};

template< typename FuncIterator >
FunctorFunctor< FuncIterator > functor_functor( FuncIterator fi )
{
return FunctorFunctor< FuncIterator >( fi );
}
 
A

alan.patterson5

Ok, the solution is to write my own STL like function. I like the apply
idea.

If I were to return values from the function and store these in a
result vector then I could use transform a la:

transform (values.begin(), values.end(), functors.begin(),
results.begin(), my_apply());

where:

struct my_apply
{
template< typename T, typename F >
T operator()(T& x, F& f) {
return f(x);
}
};

Does this work with boost::lambda?

transform (values.begin(), values.end(), functors.begin(),
results.begin(), _2(_1) );

Thanks,
Alan
I have a vector of N values and a vector of N functors. I want to apply
each functor to its corresponding value. What would be the 'correct'
STL way to do this.
for_each takes on functor and applies it to every element.
So presumably transform is a better option but it also takes one
functor.
This is obviously easily solved by a variety of methods but I am
interested in how the STL would best solve this problem.
e.g.
// fill vector with some values
vector<int> x (values.begin(), values.end());
vector<functor> funcs;
// fill funcs with different functors, or functors with different
parameters
// would like to do STL equivalent of
for (int i=0; i<x.size(); ++i) {
funcs(x);
}There is a transform that takes iterators into two containers, but it

assumes that the functions will produce outputs and you don't seem to be
doing that. As such, I agree with Pete's post.
 
P

Pete Becker

Earl said:
Do you need to increment both?

Yes, you need to increment both. If you like, you can skip the second
comparison, but the information is there, so why not use it?
transform that takes 2 inputs only
increments one and relies on "UB" if the unchecked sequence is shorter
than the first.

It doesn't rely on UB. In fact, I'm not even sure what that means. It
says that the behavior is undefined if the second sequence is too short.
Also although it can be written in one line, I think it's better to use
pre-increment because it avoids a copy of the iterator, and you don't
know how expensive that might be from a template. Although it is more
lines in your code, I don't see that it will generate more lines of
object code. So how about:

template< typename Iter1, typename Iter2 >
void apply( Iter1 first1, Iter1 last1, Iter2 first2 )
{
while ( first1 != last1 )
{
(*first1)(*first2);
++first1;
++first2;
}
}

Write it however you like.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top