Более простой способ сделать обратные вызовы для векторов (или, может быть, что-то еще в STL)? C ++ - PullRequest
4 голосов
/ 22 января 2010

Я делаю простую криминальную симулятор.

На протяжении всего этого я продолжаю делать одно и то же снова и снова:

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

Только один пример. Я ненавижу иметь все эти циклы for повсеместно OMG QQ, в любом случае делать что-то вроде:

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

Я не очень хорошо разбираюсь в STL.

Ответы [ 5 ]

8 голосов
/ 22 января 2010

Время начинать знать алгоритмы stl:

#include <algorithm>

...

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

Идея состоит в том, чтобы создать объект, называемый "функтор", который может выполнять определенное действие для каждого из элементов в диапазоне drugSack.begin(), drugSack.end().

Этот функтор может быть создан с использованием таких конструкций stl, как mem_fun_ptr, в результате чего функтор принимает аргумент ThisClass* и Drug*, а обертка вокруг него заменяет Class* на this .

5 голосов
/ 22 января 2010

Честно говоря, C ++ в настоящее время довольно плох в подобных вещах. Он определенно может это сделать, как указано в ответе xtofl, но часто это очень неуклюже.

Boost имеет для каждого макроса , что очень удобно:

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

// ...

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

Или, может быть, Boost.Bind , хотя это немного сложнее, но для вашего случая это выглядит очень хорошо:

#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 создаст функтор, который вызывает функцию-член ThisClass, sell для экземпляра класса, на который указывает this, и заменит _1 аргументом, полученным из for_each .

Самый общий метод - лямбда. У Boost есть лямбда-библиотека . Я не буду включать здесь примеры, потому что для вашего конкретного случая boost bind работает, и лямбда-код был бы тем же самым кодом. Тем не менее, Ламба может сделать гораздо больше! Они в основном создают функции на месте (реализованные как функторы), но гораздо сложнее для изучения.

На мой взгляд, for-each и bind намного чище, чем "стандартные" методы C ++. На данный момент, я бы порекомендовал, по порядку: для каждого, связывание, стандартный C ++, лямбда-выражения.

В C ++ 0x, следующем стандарте C ++, все это снова будет хорошо со встроенной лямбда-поддержкой:

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

Или новый диапазон для циклов:

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

Но мы должны подождать пару лет, прежде чем это станет возможным. :( Кроме того, я думаю, что цикл for, основанный на диапазоне, проще всего читать. Вот почему я рекомендую boost for-each, поскольку он имитирует это поведение и синтаксис (в основном).

Кроме того, совершенно не связано: стиль, в который вы включаете this->, прежде чем все, по моему опыту, обычно считается плохой практикой. Компилятор сделает это за вас, все, что вы делаете - это загромождаете свой код и вносите вероятность ошибок. Вещи читаются намного лучше без него.

2 голосов
/ 22 января 2010

Вы можете использовать std :: for_each из STL, который применяет функцию к диапазону. Смотрите следующее описание: http://www.cplusplus.com/reference/algorithm/for_each/.

Вам также потребуется использовать std :: mem_fun или std :: mem_fun_ptr для получения функции-члена вашего класса.

Для более сложных случаев взгляните на Boost Bind , который обеспечивает расширенное связывание для создания объектов функций.

1 голос
/ 22 января 2010

Для простого случая циклического прохождения всего контейнера я бы просто написал цикл. Это, к сожалению, многословно, но не подвержено ошибкам, если вы всегда пишете это одинаково. Я всегда пишу такие циклы следующим образом:

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

(или const_iterator, где необходимо).

Вы можете попробовать BOOST_FOREACH в качестве альтернативы.

1 голос
/ 22 января 2010

Ну, во-первых, я запутался: что такое sell?Если это функция-член какого-то класса, вам нужно сделать в этом классе drugSack, и в этом случае вы можете сделать что-то вроде следующего:

Что-то вроде for_each для перебора по drugSackв сочетании с mem_fun для получения sell:

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

Если продажа - это просто обычная функция, вы можете просто поместить ее в третий аргумент for_each.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...