Dave said:
Hello all,
When working with the STL, under what circumstances may I use a function
object that modifies its internal state from one call to the next? I know
this can be done with for_each<>(). I know it cannot be done if the
function object happens to be a predicate.
I do not understand why it *cannot be done* if the function object is a
predicate. Consider:
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
struct RandomPredicate {
RandomPredicate ( unsigned long _seed ) {
std::srand( _seed );
}
bool operator() ( int ) {
return( std::rand() < ( RAND_MAX >> 2 ) );
}
}; // RandomPredicate
int main ( void ) {
RandomPredicate P ( 1234 );
std::vector< int > i_vect;
for ( unsigned i = 0; i < 20; ++i ) {
i_vect.push_back( i );
}
std:
stream_iterator<int> o_iter ( std::cout, " " );
std::remove_copy_if( i_vect.begin(), i_vect.end(), o_iter, P );
}
Here a predicate object is used to make a random selection. Note that
std::remove_copy_if does not assume that the calling the same predicate
twice on the same object will yield identical results. At least, I did not
see that assumption stated in the standard.
Or consider this:
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
template < typename T >
struct CountingCompare {
// NOTE: [static to avoid hassle]
/*
std::sort receives a copy of the function object. To ensure that
we see the counter afterwards, we either have to use a pointer
(hassle) or a static variable (quick hack).
*/
static unsigned long count;
bool operator() ( T const & a,
T const & b ) const {
++ count;
return( a < b );
}
}; // CountingCompare
template < typename T >
unsigned long CountingCompare<T>::count = 0;
int main ( void ) {
CountingCompare<int> int_comp;
std::vector<int> i_vect;
for ( unsigned i = 0; i < 2000; ++i ) {
i_vect.push_back( i );
}
std::random_shuffle( i_vect.begin(), i_vect.end() );
std::sort( i_vect.begin(), i_vect.end(), int_comp );
std::cout<< "Sort needed " << int_comp.count << " comparisons\n";
}
Here, a statefull binary predicate is used to count how many comparisons
are done by std::sort. This works since the object still behaves like
an order relation. That is has a state, which changes, is irrelevant to the
algorithm.
Is there a general rule that says when a function object can or cannot
modify state?
No, those rules have to be stated for each algorithm / method seperately.
Best
Kai-Uwe Bux