10

I am trying to remove elements from a std::list and keep some stats of deleted elements.

In order to do so, I use the remove_if function from the list, and I have a predicate. I would like to use this predicate to gather statistics. Here is the code for the predicate:

  class TestPredicate
  {
  private:
    int limit_;

  public:
    int sum;
    int count;
    TestPredicate(int limit) : limit_(limit), sum(0), count(0) {}

    bool operator() (int value) 
    {
      if (value >= limit_)
      {
        sum += value;
        ++count;       // Part where I gather the stats
        return true;
      }
      else
        return false;
    }
  };

And here is the code for the algo:

std::list < int > container;
container.push_back(11);
TestPredicate pred(10);
container.remove_if(pred)
assert(pred.count == 1);

Unfortunately, the assertion is false because the predicate is passed by value. Is there a way to force it to be passed by reference ?

0x26res
  • 11,925
  • 11
  • 54
  • 108
  • 1
    I don't know if it can be done directly, but you could use a wrapper containing a reference or pointer to the real predicate to get the desired effect. – Daniel Fischer Nov 29 '11 at 15:34
  • That's a good idea. Then I could create a template to wrap any predicate reference... Which makes me wonder if such a template exists in stl or boost... – 0x26res Nov 29 '11 at 15:41
  • @jules: Feel free to amend your templated solution to your post! (I'm a bit irritated though that `std::tr1::ref` doesn't do the job in C++03.) **Update:** Found it! Editing... – Kerrek SB Nov 29 '11 at 15:54

2 Answers2

18

Pass a reference wrapper, available from <functional>:

container.remove_if(std::ref(pred));

If you only have C++98/03 but your compiler has TR1, you can use <tr1/functional> and std::tr1::ref if you make a small amendment to your predicate:

#include <tr1/functional>

class TestPredicate : public std::unary_function<int, bool>
{                 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // ...
}

container.remove_if(std::tr1::ref(pred));

If all else fails, then you can hack up a manual solution with relative ease:

struct predref
{
  TestPredicate & p;
  bool operator()(int n) { return p(n); }
  predref(TestPredicate & r) : p(r) { }
};

container.remove_if(predref(pred));
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2

The functors passed to the algorithms can be copied inside the algorithm an indeterminate number of times, so you cannot store state directly in the functor. You can, on the other hand, store the state outside of the functor, by using a pointer or reference to some external state structure.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489