Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke std::function in an std::for_each

Tags:

c++

std

c++11

I have in essence the following code:

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

The use of ExecuteGlobal feels totally redundant here, but I can't find the right syntax to drop out the call.

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

Both fail to compile.

There is also a more complex case:

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

Is it possible to do without the helper functions in these cases?

like image 892
Rob Walker Avatar asked Apr 20 '12 17:04

Rob Walker


3 Answers

Sure, a lambda:

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

Or even better, range for:

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

// well, I think you can figure out the second one
like image 81
Cat Plus Plus Avatar answered Sep 18 '22 13:09

Cat Plus Plus


Why don't you use lambda as:

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

Or using range-based for loop as:

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

which looks more concise and cleaner.

like image 41
Nawaz Avatar answered Sep 22 '22 13:09

Nawaz


Here's something I just thought up, tell me if it's something like what you're looking for:

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

Then you could use it like this:

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

And for functions with arguments:

call_each(triggers.begin(), triggers.end(), zot);
like image 30
Benjamin Lindley Avatar answered Sep 19 '22 13:09

Benjamin Lindley