Более простой способ делать обратные вызовы для векторов (или, может быть, что-то еще в 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 в качестве альтернативы.