Easier way to do callbacks for vectors (or maybe s

2019-06-27 15:31发布

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.

标签: c++ stl vector
5条回答
混吃等死
2楼-- · 2019-06-27 16:12

Well, first I'm confused: what's sell? Is it meant to be a member function of some class, you need to make drugSack that class, in which case you can do something like the following --

Something like for_each to iterate over drugSack, combined with mem_fun to get sell:

for_each(drugSack.begin(), drugSack.end(), mem_fun(&Drug::sell))

If sell is just an ordinary function, you can just put it in the third argument of for_each.

查看更多
趁早两清
3楼-- · 2019-06-27 16:16

You could use std::for_each from the STL which applies a function to a range. See the following description: http://www.cplusplus.com/reference/algorithm/for_each/.

You will also need to use std::mem_fun or std::mem_fun_ptr to obtain the member function of your class.

For more advanced cases, have a look at Boost Bind which provides an advanced binder for creating function objects.

查看更多
闹够了就滚
4楼-- · 2019-06-27 16:18

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.

查看更多
Animai°情兽
5楼-- · 2019-06-27 16:24

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.

查看更多
戒情不戒烟
6楼-- · 2019-06-27 16:27

For the simple of case of looping through an entire container, I'd just write the loop. It's unfortunately long-winded, but not prone to mistakes if you always write it the same way. I always write such loops as follows:

Container c;
for (Container::iterator i = c.begin(), end = c.end(); i != end; ++i)
    ...

(or const_iterator where appropriate).

You could try BOOST_FOREACH as an alternative.

查看更多
登录 后发表回答