Sign in to follow this  
blackfe2010

How to use boost::unordered_map with for_each?

Recommended Posts

blackfe2010    150
Hi

[CODE]
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;
}
[/CODE]

Who can tell me how to write the for_each?
p1 and p2 are the parameters should send to TEST::doSomething.

Share this post


Link to post
Share on other sites
Brother Bob    10344
The function is called with an [i]std::pair<Tk, Tv>[/i] object, where [i]Tk [/i]is the key type and [i]Tv [/i]is the value type. For example, using a lambda expression:
[code]
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 */ }
);
[/code]
To call the member function [i]doSomething[/i] on the [i]TEST [/i]object, and passing [i]p1 [/i]and [i]p2 [/i]to it, you can implement the function to call [i]doSomething [/i]on the value and capture the parameters [i]p1 [/i]and [i]p2 [/i]with the lambda expression.
[code]
for_each(
g_map.begin(),
g_map.end()
[=](std::pair<int, std::shared_ptr<TEST>> const &foo){ foo.second->doSomething(p1, p2); }
);
[/code]
Replace [i]std::[/i] with [i]boost::[/i] at suitable places. I don't have boost installed on this machine so can only verify it with the std equivalents.

Share this post


Link to post
Share on other sites
Brother Bob    10344
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.

Share this post


Link to post
Share on other sites
blackfe2010    150
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? Edited by blackfe2010

Share this post


Link to post
Share on other sites
Brother Bob    10344
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.
[code]
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));
[/code]
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.

Share this post


Link to post
Share on other sites
Bregma    9199
[quote name='blackfe2010' timestamp='1352211486' post='4998033']
ok, i think i need to learn some lambda expression.
[/quote]
Yes, assuming you have a compiler that supports the current C++ standard.
[quote]
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).
[quote]
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.
[quote]
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. Edited by Bregma

Share this post


Link to post
Share on other sites
[quote name='Bregma' timestamp='1352220767' post='4998097']
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.
[/quote]Long lambdas do not decrease code readability. The difference between this:
[code]for (auto it=begin(container); it!=end(container); ++it)
{
... 20 lines ...
}[/code]and this:[code]for_each(begin(container),end(container),[](element &x)
{
... 20 lines ...
});[/code]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:[code]void someFunc()
{
auto snarf = [](foo &amp;amp;f) { /* snarfing a foo */ };
for_each(begin(manyFoos), end(manyFoos), snarf);
snarf(*begin(manyFoos)); // first foo needs to be snarfed twice
snarf(anotherFoo);
}[/code] Edited by Stroppy Katamari

Share this post


Link to post
Share on other sites
blackfe2010    150
Hi, I'm come back.

Sorry, I found i use vs2008 in one of my computer.
So I can't use c++11 like:
[quote name='Álvaro' timestamp='1352198432' post='4997966']<br /> for (auto entry : g_map) entry.second->doSomething(p1, p2);<br />[/quote]
and
[quote name='Brother Bob' timestamp='1352197847' post='4997965']<br />for_each( g_map.begin(), g_map.end() [=](std::pair<int, std::shared_ptr<TEST>> const &foo){ foo.second->doSomething(p1, p2); } );<br />[/quote]


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

At first, I want to bind [url="http://www.boost.org/doc/libs/1_52_0/doc/html/lambda/le_in_details.html#lambda.members_variables_as_targets"]member variables[/url] std::pair<int,boost::shared_ptr<TEST>>::second
[source lang="cpp"]
for_each(
g_map.begin(),
g_map.end(),
boost::bind(&std::pair<int,boost::shared_ptr< TEST > >::second,_1));
[/source]
But it's failed, why?

Share this post


Link to post
Share on other sites
alvaro    21246
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?

[code]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);
[/code]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this