views:

187

answers:

2

I am struggling to find out why I can't get transform to work with a template class.

Here's a simplified version of the template class :

template<typename T>
class base
{
public :
  base() : all_() {}
  ~base() {}
public:
  bool add(T t)
  {
    typename vector<T>::iterator itr 
      = lower_bound(all_.begin(), all_.end(), t);
    if ( itr == all_.end() || *itr != t )
      {
        all_.push_back(t);
        cout << "ok" << endl;
        return true;
      }
    cout << "failed" << endl;
    return false;
  }
  static bool addTo(base<T> *c, T t)
  {
    return c->add(t);
  }
private :
  vector<T> all_;
};

And this is where I am trying to use transform to capture all the bool output from the add member function :

main()
{
  base<int> test;
  vector<bool> results;
  vector<int> toAdd;
  toAdd.push_back(10);
  toAdd.push_back(11);
  toAdd.push_back(10);
  transform( toAdd.begin(), toAdd.end(),
             back_inserter(results),
             bind1st( (bool(*)(base<int>*,int))base<int>::addTo, &test ) );
}

The aim is to insert each member of the toAdd container suing the either base::add or base::addTo, and capture the bool results in the vector results

+4  A: 

Try:

  transform( toAdd.begin(), toAdd.end(),
         back_inserter(results),
         bind1st( mem_fun(&base<int>::add), &test ) );

The problem isn't the template, it's that bind1st relies on extra support to work (see http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html). AFAIK it can't ever operate on plain old function pointers.

boost::bind can do more things, if you want to bring that in. For this situation you don't need it, though: mem_fun turns a non-static member function into an adaptable binary function. addTo therefore isn't needed either, but if you did need to use a static member function in a similar situation then there's ptr_fun.

Steve Jessop
That works. Thanks for the tips, especially the pedantic one.
youngthing
And the *reason* it works is that `bind1st` doesn't accept ordinary function pointers. It requires functor objects. The `mem_fun` and `ptr_fun` functions turn function pointers into functors suitable for use with the binders.
Rob Kennedy
@RobKennedy: thanks, that makes a lot of sense, and something I haven't picked up from the Josutis STL book yet. I would give you and onebyone a rec if a could!
youngthing
@Rob: thanks, you beat me to it while I was looking up the SGI docs to remember what the darn thing's called. Adaptable.
Steve Jessop
And good point about ptr_fun being relevant too, I've added that to the answer.
Steve Jessop
A: 

Add the following to your base class:

typedef base<T>* first_argument_type;
typedef T second_argument_type;
typedef bool result_type;

bool operator () (base<T> *c, T t) const {
    return c->add(t);
}

and change transform to:

transform(toAdd.begin(), toAdd.end(),
          back_inserter(results), bind1st(base<int>(), &test ));
Andreas Brinck
That would be okay if my class (base) was only going to be storing a container - I would not mind committing operator() to just adding an item. My proper code though has base responsible for a lot more.
youngthing
You wouldn't have to place add in the 'base' class you could create a small struct, say 'Adder' which contains the code I supplied. Then replace base<int> with 'Adder'. But the mem_fun adapter works as well ;)
Andreas Brinck