Более простой способ делать обратные вызовы для векторов (или, может быть, что-то еще в STL)? С++

Я делаю простую игру с симуляцией.

Всюду по этому я продолжаю делать то же самое снова и снова:

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

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

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

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

Ответ 1

Время, чтобы начать знание 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.

Ответ 2

Честно говоря, С++ в настоящее время довольно плох в таких вещах. Он может определенно сделать это, как указано в ответе 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 имеет lambda library. Я не буду включать образцы здесь, потому что для вашего конкретного случая boost bind работает, а лямбда - это тот же код. Тем не менее, ламба может многое сделать! Они в основном создают функции на месте (реализованы как функторы), но гораздо сложнее изучить.

Как для каждого, так и для привязки гораздо проще, чем "стандартные" методы на С++, на мой взгляд. На данный момент я бы рекомендовал, чтобы: для каждого, связать, стандартный С++, лямбда.

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

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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