2012-04-20 21 views
5

mam w istocie następujący kod:Wywołanie std :: funkcja w std :: 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)); 

Zastosowanie ExecuteGlobal czuje się całkowicie zbędny tutaj, ale nie mogę znaleźć właściwą składnię odpaść telefon.

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

Obie nie kompilują się.

Jest też bardziej złożona sprawa:

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)); 

Czy można zrobić bez funkcji pomocniczych w tych sprawach?

+2

Możesz rzucić okiem na nową składnię 'for' w najnowszym standardzie C++ (C++ 11): http://en.wikipedia.org/wiki/C%2B%2B11#Range -based_for-loop – lvella

+4

Dla twojego pierwszego przykładu, rzeczą, która jest zbędna jest użycie std :: bind: 'std :: for_each (triggers.begin(), triggers.end(), ExecuteGlobal);' –

+0

@ benjamin-lindley : dziękuję, wróciłem z bardziej złożonej sprawy i straciłem tam dodatkową nadmiarowość! –

Odpowiedz

7

Jasne, lambda:

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

Albo jeszcze lepiej, zakres:

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

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

Funkcja lambda działa ... ale biorąc pod uwagę, że już pełniłem funkcję jako zmienna iteratora, po prostu czułam, że powinien być sposób użycia jej bezpośrednio, bez konieczności tworzenia nowego opakowania. –

+1

@RobWalker: Jest to również możliwe, ale do tego musisz użyć Boost. Czy możesz tego użyć? – Nawaz

+0

Właściwie potrzebujesz najnowszego kompilatora, ponieważ te rzeczy pochodzą z najnowszego standardu C++ (2011). – lvella

4

Dlaczego nie używasz lambda jak:

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

lub używając pasmo oparty na pętli jako:

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

który wygląda bardziej zwięźle i czysto.

1

Oto coś po prostu wymyślił, powiedz mi, czy jest to coś, czego szukasz:

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)...); 
} 

następnie można go używać tak:

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

A dla funkcji z argumenty:

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

Zły pomysł. Używasz szablonu funkcji 'std :: forward' w niewłaściwy sposób. Jeśli wartość rwart jest przekazywana do 'call_each', _object_ może zostać przeniesiony w pierwszej iteracji, a pozostałe iteracje będą używały niewłaściwego _object_. – nosid

0

tak, więc nie będę zapominać, że opcja:

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)); 
Powiązane problemy