Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Errors using std::for_each lambda function

Tags:

c++

c++11

boost

wt

I have a little problem and I can't figure out why this code doesn't work:

std::for_each(users.begin(), users.end(), [](Wt::WString u)
{
    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(u);
});

Errors that I get while compiling:

GameWidget.cpp: In lambda function:
GameWidget.cpp:352:30: error: 'users' is not captured
GameWidget.cpp:353:4: error: 'this' was not captured for this lambda function
GameWidget.cpp: In member function 'virtual void GameWidget::updateUsers()':
GameWidget.cpp:354:3: warning: lambda expressions only available with -std=c++11 or -std=gnu++11 [enabled by default]
GameWidget.cpp:354:4: error: no matching function for call to 'for_each(std::set<Wt::WString>::iterator, std::set<Wt::WString>::iterator, GameWidget::updateUsers()::<lambda(Wt::WString)>)'
GameWidget.cpp:354:4: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
                 from GameWidget.h:11,
                 from GameWidget.cpp:9:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
GameWidget.cpp:354:4: error: template argument for 'template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)' uses local type 'GameWidget::updateUsers()::<lambda(Wt::WString)>'
GameWidget.cpp:354:4: error:   trying to instantiate 'template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)'

I am using gcc 4.7.3, so probably C++11 support is available for my compiler.

userBox_ is a collection and BOOST_FOREACH works properly for this code:

BOOST_FOREACH(Wt::WString i, users)
{
    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(i);
}

Thanks for any answer, I'm so curious why is that.

like image 565
gadon Avatar asked Dec 27 '22 03:12

gadon


2 Answers

The lambda you've written does not capture any context variables. To do this, the easiest is to add & to the lambda's capture list. This will capture all context variables by reference and you'll be able to access them within the lambda.

std::for_each(users.begin(), users.end(), [&](Wt::WString u)
{
    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(u);
});

I don't understand why you're printing users.size() within the loop, because it looks like the output is going to be the same every iteration. If you move that outside the loop, and want more fine grained control over what the lambda captures, you can modify the capture list to only capture the this pointer. This will let you access the member variable userBox_.

std::cout << "ilosc: " << users.size() << std::endl;
std::for_each(users.begin(), users.end(), [this](Wt::WString u)
{
    userBox_->addItem(u);
});

MSDN has an excellent article explaining the lambda expression syntax in great detail.

Finally, in your case, there's no need for std::for_each and a lambda. It would be a lot more succinct to use a range based for loop to add the items to the collection.

for( auto const& u: users ) {
  userBox_->addItem(u);
}
like image 125
Praetorian Avatar answered Dec 29 '22 03:12

Praetorian


Everything you needed to know is in the errors you received.

You told the lambda, explicitly, not to capture anything, by using "[]", which means the only variables it has access to inside the function body are parameters and globals.

It doesn't matter what type userBox_ is, it's a member variable, so the lambda needs to capture "this".

Lastly, you're passing by value, which means you're going to duplicate each and every Wt::WString. You might want instead to use

std::for_each(users.begin(), users.end(), [&](const Wt::WString& u) {
...
});

The "&" captures by reference and will capture "this" for you.

http://en.cppreference.com/w/cpp/language/lambda

like image 39
kfsone Avatar answered Dec 29 '22 02:12

kfsone