•Unlike Functions Functor can have state.
This is very interesting because std::binary_function, std::less and std::equal_to has a template for an operator() that is const. But what if you wanted to print a debug message with the current call count for that object, how would you do it?
Here is template for std::equal_to:
struct equal_to : public binary_function<_Tp, _Tp, bool>
{
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x == __y; }
};
I can think of 3 ways to allow the operator() to be const, and yet change a member variable. But what is the best way? Take this example:
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cassert> // assert() MACRO
// functor for comparing two integer's, the quotient when integer division by 10.
// So 50..59 are same, and 60..69 are same.
// Used by std::sort()
struct lessThanByTen: public std::less<int>
{
private:
// data members
int count; // nr of times operator() was called
public:
// default CTOR sets count to 0
lessThanByTen() :
count(0)
{
}
// @override the bool operator() in std::less<int> which simply compares two integers
bool operator() ( const int& arg1, const int& arg2) const
{
// this won't compile, because a const method cannot change a member variable (count)
// ++count;
// Solution 1. this trick allows the const method to change a member variable
++(*(int*)&count);
// Solution 2. this trick also fools the compilers, but is a lot uglier to decipher
++(*(const_cast<int*>(&count)));
// Solution 3. a third way to do same thing:
{
// first, stack copy gets bumped count member variable
int incCount = count+1;
const int *iptr = &count;
// this is now the same as ++count
*(const_cast<int*>(iptr)) = incCount;
}
std::cout << "DEBUG: operator() called " << count << " times.\n";
return (arg1/10) < (arg2/10);
}
};
void test1();
void printArray( const std::string msg, const int nums[], const size_t ASIZE);
int main()
{
test1();
return 0;
}
void test1()
{
// unsorted numbers
int inums[] = {33, 20, 10, 21, 30, 31, 32, 22, };
printArray( "BEFORE SORT", inums, 8 );
// sort by quotient of integer division by 10
std::sort( inums, inums+8, lessThanByTen() );
printArray( "AFTER SORT", inums, 8 );
}
//! @param msg can be "this is a const string" or a std::string because of implicit string(const char *) conversion.
//! print "msg: 1,2,3,...N", where 1..8 are numbers in nums[] array
void printArray( const std::string msg, const int nums[], const size_t ASIZE)
{
std::cout << msg << ": ";
for (size_t inx = 0; inx < ASIZE; ++inx)
{
if (inx > 0)
std::cout << ",";
std::cout << nums[inx];
}
std::cout << "\n";
}
Because all 3 solutions are compiled in, it increments count by 3. Here's the output:
gcc -g -c Main9.cpp
gcc -g Main9.o -o Main9 -lstdc++
./Main9
BEFORE SORT: 33,20,10,21,30,31,32,22
DEBUG: operator() called 3 times.
DEBUG: operator() called 6 times.
DEBUG: operator() called 9 times.
DEBUG: operator() called 12 times.
DEBUG: operator() called 15 times.
DEBUG: operator() called 12 times.
DEBUG: operator() called 15 times.
DEBUG: operator() called 15 times.
DEBUG: operator() called 18 times.
DEBUG: operator() called 18 times.
DEBUG: operator() called 21 times.
DEBUG: operator() called 21 times.
DEBUG: operator() called 24 times.
DEBUG: operator() called 27 times.
DEBUG: operator() called 30 times.
DEBUG: operator() called 33 times.
DEBUG: operator() called 36 times.
AFTER SORT: 10,20,21,22,33,30,31,32
for_each
really return the average? Don't you needaccumulate
? See sgi.com/tech/stl/accumulate.html. Here, your second line applies CalculateAvarage()() to each member of the sequence, so you'd need some clever running average calculation, plus an instance of CalculateAverage that you can query after thefor_each
.for_each
will return a copy of your functor. – juanchopanzastruct Average { double total; uintmax_t count; Average() : total(0), count(0) {} Average operator+(double d) { total += d; count += 1; }; operator double() { return total / count; /* undefined if 0! */ }};
. You don't need to use the binary operator parameter at all if you don't want, and the operator doesn't need to track the count, the accumulator can (and should) do it. I think this is about equally clear with the functor you'd pass tofor_each
, the difference is you implementoperator+
instead ofoperator()
. – Steve Jessop