Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easier way to do callbacks for vectors (or maybe something else in the STL)? C++

Tags:

c++

stl

vector

I'm making a simple crime sim game.

Throughout it I keep doing the same thing over and over:

// vector<Drug*> drugSack;
for (unsigned int i = 0; i < this->drugSack.size(); i++)
            this->sell(drugSack[i]);

Just one example. I hate having all these for loops all over the place omg QQ, anyway to do something like:

drugSack->DoForAll((void*)myCallBack);

I'm not well versed in the STL.

like image 232
y2k Avatar asked Dec 04 '22 13:12

y2k


2 Answers

Time to start knowing the stl algorithms:

#include <algorithm>

...

std::for_each( drugSack.begin(), drugSack.end(), 
  std::bind1st( std::mem_fun_ptr( &ThisClass::Sell ), this ) );

The idea is to create an object, called a "functor", that can do a certain action for each of the elements in the range drugSack.begin(), drugSack.end().

This functor can be created using stl constructs like mem_fun_ptr, resulting in a functor taking a ThisClass* and a Drug* argument, and a wrapper around it that will substitute/bind the Class* for this.

like image 188
xtofl Avatar answered Mar 02 '23 00:03

xtofl


Honestly, C++ is currently pretty bad at this kind of stuff. It can definitely do it, as outlined in xtofl's answer, but it's often very clumsy.

Boost has a for-each macro that is quite convenient:

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

// ...

foreach(Drug* d, drugSack)
{
    sell(d);
}

Or perhaps Boost.Bind, though this is slightly more complex, it reads very nice for your case:

#include <boost/bind.hpp>

// ...

// ThisClass refers to whatever class this method is in
std::for_each(drugSack.begin(), drugSack.end(),
                boost::bind(&ThisClass::sell, this, _1));

Bind will make a functor that calls the member function of ThisClass, sell, on the instance of the class pointed to by this, and will replace _1 with the argument it gets from for_each.

The most general method is with lambda's. Boost has a lambda library. I won't include samples here because for your specific case boost bind works, and the lambda's would be the same code. That said, lamba's can do much more! They basically create in-place functions (implemented as functors), but are much more complex to learn.

Both for-each and bind are far cleaner than the "standard" C++ methods, in my opinion. For now, I'd recommend, in order: for-each, bind, standard C++, lambda's.

In C++0x, the next C++ standard, all this will be nice again with built-in lambda support:

std::for_each(drugSack.begin(), drugSack.end(),
                [this](DrugSack* d){ sell(d); });

Or the new range-based for loops:

for(DrugSack* d : drugSack)
{
    sell(d);
}

But we must wait a couple years before this is an option. :( Also, I think the range-based for-loop is the easiest thing to read. This is why I recommend boost for-each, because it mimics this behavior and syntax (mostly).

Also, totally unrelated: the style where you include this-> before everything is, in my experience, generally considered bad practice. The compiler will do it for you, all you're doing is cluttering up your code and introducing the chance of mistakes. Things read much better without it.

like image 24
GManNickG Avatar answered Mar 01 '23 22:03

GManNickG