2012-04-20 2 views
5

Я имею в сущности следующий код:Invoke станд :: функция в станд :: for_each

typedef std::function<void()> fnGlobalChangeEvent; 
typedef std::vector<fnGlobalChangeEvent> GlobalTriggers; 

inline void ExecuteGlobal(fnGlobalChangeEvent ev) 
{ 
    ev(); 
} 

GlobalTriggers triggers; 
std::for_each(triggers.begin(), triggers.end(), std::bind(&ExecuteGlobal, _1)); 

Использование ExecuteGlobal чувствует себя совершенно излишним, но я не могу найти правильный синтаксис для выпадать вызов.

std::for_each(triggers.begin(), triggers.end(), ExecuteGlobal(_1)); 
std::for_each(triggers.begin(), triggers.end(), std::bind(_1)); 

Оба не могут скомпилировать.

Существует также более сложный случай:

typedef std::function<void (Zot&)> fnChangeEvent; 
typedef std::vector<fnChangeEvent> Triggers; 

inline void Execute(fnChangeEvent ev, Zot& zot) 
{ 
    ev(zot); 
} 

Triggers triggers; 
std::for_each(triggers.begin(), triggers.end(), std::bind(&Execute, _1, zot)); 

Можно ли обойтись без вспомогательных функций в этих случаях?

+2

Возможно, вы захотите взглянуть на новый синтаксис 'for' в последнем стандарте C++ (C++ 11): http://en.wikipedia.org/wiki/C%2B%2B11#Range -based_for-loop – lvella

+4

Для вашего первого примера, избыточным является использование std :: bind: 'std :: for_each (triggers.begin(), triggers.end(), ExecuteGlobal);' –

+0

@ benjamin-lindley : спасибо, я работал от более сложного случая и пропустил лишнюю избыточность там! –

ответ

7

Конечно, лямбда:

std::for_each(
    triggers.begin(), triggers.end(), 
    [](fnChangeEvent ev) { ev(); } 
); 
std::for_each(
    triggers.begin(), triggers.end(), 
    [&zot](fnChangeEvent ev) { ev(zot); } 
); 

Или еще лучше, диапазон:

for (auto ev : triggers) { 
    ev(); 
} 

// well, I think you can figure out the second one 
+0

Лямбда работает ... но учитывая, что у меня уже была функция, действующая как переменная итератора, она просто чувствовала, что должен быть способ ее использования напрямую, без необходимости создавать новую оболочку. –

+1

@RobWalker: Это также возможно, но для этого вы должны использовать Boost. Можете ли вы использовать это? – Nawaz

+0

На самом деле вам понадобится совсем недавний компилятор, поскольку эти вещи взяты из новейшего стандарта C++ (2011). – lvella

4

Почему бы вам не использовать лямбда, как:

std::for_each(triggers.begin(), 
       triggers.end(), 
       [&](fnChangeEvent & e) 
       { 
        e(zot); 
       }); 

Или с помощью пастбищам основанный на петле как:

for (auto& e : triggers) { e(zot); } 

, который выглядит более кратким и чистым.

1

Вот что-то я просто придумал, скажите мне, если это что-то вроде того, что вы ищете:

template<typename IT, typename ...Args> 
void call_each(IT begin_, IT end_, Args&&... args) 
{ 
    for (auto i = begin_; i!=end_; ++i) 
     (*i)(std::forward<Args>(args)...); 
} 

Тогда вы могли бы использовать его как это:

call_each(triggers.begin(), triggers.end()); 

И для функций с аргументы:

call_each(triggers.begin(), triggers.end(), zot); 
+1

Плохая идея. Вы используете шаблон функции 'std :: forward' неправильным образом. Если rvalue передается в 'call_each', _object_ можно удалить в первой итерации, а другие итерации будут использовать неправильный _объект_. – nosid

0

Просто, так что я не буду забывать, что вариант:

typedef std::function<void()> fnGlobalChangeEvent; 
typedef std::vector<fnGlobalChangeEvent> GlobalTriggers; 

GlobalTriggers triggers; 
using namespace std::placeholders; 
std::for_each(triggers.begin(), triggers.end(), std::bind(&fnGlobalChangeEvent::operator(), _1)); 
Смежные вопросы