Skip to main content
GameDev.net gamedev.net
🔒 Locked

How to use boost::unordered_map with for_each?

Started by blackfe2010 Nov 6, 2012 at 9:14 AM 12 replies 6.2k views
Original Post
blackfe2010
blackfe2010
Hi


class TEST
{
public:
TEST() {};
void doSomething(int a,int b);
};
boost::unordered_map<int,boost::shared_ptr<TEST>> g_map;
int main()
{
int p1=0;
int p2=1;
g_map[0]=boost::make_shared<TEST>();
g_map[1]=boost::make_shared<TEST>();
for_each(g_map.begin(),g_map.end(),how to write?);
returns 0;
}


Who can tell me how to write the for_each?
p1 and p2 are the parameters should send to TEST::doSomething.
Brother Bob
Brother Bob
The function is called with an std::pair object, where Tk is the key type and Tv is the value type. For example, using a lambda expression:

for_each(
g_map.begin(),
g_map.end()
[](std::pair<int, std::shared_ptr<TEST>> const &foo){ /* key in foo.first and value in foo.second */ }
);

To call the member function doSomething on the TEST object, and passing p1 and p2 to it, you can implement the function to call doSomething on the value and capture the parameters p1 and p2 with the lambda expression.

for_each(
g_map.begin(),
g_map.end()
[=](std::pair<int, std::shared_ptr<TEST>> const &foo){ foo.second->doSomething(p1, p2); }
);

Replace std:: with boost:: at suitable places. I don't have boost installed on this machine so can only verify it with the std equivalents.
alvaro
alvaro
In C++11:
for (auto entry : g_map)
entry.second->doSomething(p1, p2);
blackfe2010
blackfe2010
thanks, it's works well.

but what's means of [=] ?
Brother Bob
Brother Bob
It is the capture part of the lambda expression syntax. I'm not sure if your question is about lambda expressions in general or if you are aware of them and just want to know why I use the equal sign in the capture part.

If you want to know about lambda expressions in general, then your best option is to just use your favorite search engine so you can read some proper written material instead of a quick forum post. But if you're just wondering about the capture part, then it simply means that the values are captured by value instead of being captured by reference (which would be [&]). The difference between a value and a reference capture is whether the variable inside the lambda expression is a copy of, or a reference to, the original variable. By value-capture is the default so it could actually have been left out.
blackfe2010
blackfe2010
ok, i think i need to learn some lambda expression.

but Is this the only solution to use "lumbda"?

And what the performance about the lumbda?

Can i use huge amount of lumbda expressions in my code?
Brother Bob
Brother Bob
alvaro's solution is better than a for_each call. But there are other options to lambda expressions to use with for_each if you really want to use it, such as a function object.

struct myfuncobj {
myfuncobj(int p1, int p2) : p1(p1), p2(p2) { }

void operator()(std::pair<int, std::shared_ptr<TEST>> const &foo) {
foo.second->doSomething(p1, p2);
}

private:
int p1, p2;
};
...
for_each(g_map.begin(), g_map.end() myfuncobj(p1, p2));

The function object is more or less equivalent to what the compiler would generate for the lambda expression, but has the drawback of being more code to write and that you have to separate the for_each-statement and its actual code.
Bregma
Bregma

ok, i think i need to learn some lambda expression.

Yes, assuming you have a compiler that supports the current C++ standard.

but Is this the only solution to use "lumbda"?
[/quote]
No. You can hand-craft a functor class (if your compiler does not support lambdas) or use std::bind (or boost::bind if your compiler does not support the current C++ standard).

And what the performance about the lumbda?
[/quote]
Generally as good as you can get. The compiler will effectively transform the expression into an inline function.

Can i use huge amount of lumbda expressions in my code?
[/quote]
Yes you can. Don't. You can use them frequently, but if the expression is more than a few (1 to 7, say) lines then from a readability standpoint you would benefit from writing a separate function and using std::bind if currying arguments is required. Short lambda expressions increase code readability, longer ones decrease it.
Stephen M. Webb
Professional Free Software Developer
Stroppy Katamari
Stroppy Katamari

Yes you can. Don't. You can use them frequently, but if the expression is more than a few (1 to 7, say) lines then from a readability standpoint you would benefit from writing a separate function and using std::bind if currying arguments is required. Short lambda expressions increase code readability, longer ones decrease it.
Long lambdas do not decrease code readability. The difference between this:
for (auto it=begin(container); it!=end(container); ++it)
{
... 20 lines ...
}
and this:for_each(begin(container),end(container),[](element &x)
{
... 20 lines ...
});
is just a matter of taste. I tend to like the for_each version when I can't use range-for.
You can use lambdas of whatever length when the functionality within is a one-off and not needed anywhere else in the code.
If the code is needed several times but only locally, you can still use a lambda and avoid polluting the outer scope with useless stuff:void someFunc()
{
auto snarf = [](foo &amp;f) { /* snarfing a foo */ };
for_each(begin(manyFoos), end(manyFoos), snarf);
snarf(*begin(manyFoos)); // first foo needs to be snarfed twice
snarf(anotherFoo);
}
Stroppy Katamari
Stroppy Katamari
The forum editor seems to be bugged. If I try to edit the typos out, it just spawns more typos. Maybe it doesn't like the lambda syntax? :-(
blackfe2010
blackfe2010
Hi, I'm come back.

Sorry, I found i use vs2008 in one of my computer.
So I can't use c++11 like:

for (auto entry : g_map) entry.second->doSomething(p1, p2);

and

for_each( g_map.begin(), g_map.end() [=](std::pair> const &foo){ foo.second->doSomething(p1, p2); } );



And I want use boost::bind to solute this problem.

At first, I want to bind member variables std::pair>::second
[source lang="cpp"]
for_each(
g_map.begin(),
g_map.end(),
boost::bind(&std::pair >::second,_1));
[/source]
But it's failed, why?
blackfe2010
blackfe2010
I'm find the problem.

I haven't wrt the default constructor...
Stroppy Katamari
Stroppy Katamari
Yeah, you can start from that and add an outer bind that binds to &TEST::doSomething.

Is there any reason you can't upgrade your Visual Studio to a new version and start using modern language features?
alvaro
alvaro
Why insist on using for_each? If the syntax is so cumbersome that you (or I) can't figure it out, why not use an old-fashioned loop?

for (boost::unordered_map<int,boost::shared_ptr<TEST> >::iterator it = g_map.begin(), end = g_map.end(); it != end; ++it)
it->second->doSomething(p1, p2);

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.