使用 std::for_each lambda 函数的错误

Posted

技术标签:

【中文标题】使用 std::for_each lambda 函数的错误【英文标题】:Errors using std::for_each lambda function 【发布时间】:2013-05-26 21:24:53 【问题描述】:

我有一个小问题,我不知道为什么这段代码不起作用:

std::for_each(users.begin(), users.end(), [](Wt::WString u)

    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(u);
);

我在编译时遇到的错误:

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

我正在使用gcc 4.7.3,所以我的编译器可能支持 C++11。

userBox_ 是一个集合,BOOST_FOREACH 适用于此代码:

BOOST_FOREACH(Wt::WString i, users)

    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(i);

谢谢你的回答,我很好奇为什么会这样。

【问题讨论】:

你试过[&amp;](Wt::WString u) ... 吗? 并像错误告诉你的那样使用-std=c++11 编译? 除了上述 cmets,您可能还打算使用 u.size(); @chris:[enabled by default] 好像表示这个警告不是问题? @paxdiablo,这意味着默认情况下会启用警告,至少从我的经验来看。 GCC 警告的某些部分可能有点误导。 【参考方案1】:

您编写的 lambda 不会捕获任何上下文变量。为此,最简单的方法是将&amp; 添加到 lambda 的捕获列表中。这将通过引用捕获所有上下文变量,您将能够在 lambda 中访问它们。

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

    std::cout << "ilosc: " << users.size() << std::endl;
    userBox_->addItem(u);
);

我不明白你为什么要在循环中打印users.size(),因为看起来每次迭代的输出都是一样的。如果您将其移到循环之外,并希望对 lambda 捕获的内容进行更细粒度的控制,您可以修改捕获列表以仅捕获 this 指针。这将允许您访问成员变量userBox_

std::cout << "ilosc: " << users.size() << std::endl;
std::for_each(users.begin(), users.end(), [this](Wt::WString u)

    userBox_->addItem(u);
);

MSDN 有一篇很棒的文章详细解释了lambda expression syntax。

最后,在您的情况下,不需要 std::for_each 和 lambda。使用基于范围的for 循环将项目添加到集合中会更简洁。

for( auto const& u: users ) 
  userBox_->addItem(u);

【讨论】:

感谢您的回答!缺少 & 和 c11 标志有助于正确构建代码。正如你所写的 users.size() 在这个例子中没有意义,我的错误。【参考方案2】:

您需要知道的一切都在您收到的错误中。

您通过使用“[]”明确告诉 lambda 不要捕获任何内容,这意味着它在函数体内可以访问的唯一变量是参数和全局变量。

userBox_是什么类型没关系,它是一个成员变量,所以lambda需要捕获“this”。

最后,您是按值传递的,这意味着您将复制每个 Wt::WString。您可能想改用

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

“&”通过引用捕获并将为您捕获“this”。

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

【讨论】:

【参考方案3】:

捕获变量 users 意味着将您的 lambda 声明为:

    [users](Wt::WString u)...

它将users 作为只读变量传递。

为了能够修改users,您需要将您的 lambda 声明为:

    [&users](Wt::WString u)...

【讨论】:

以上是关于使用 std::for_each lambda 函数的错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 std::for_each() 返回时调用转换运算符?

lambda 是不是像 C++ 中的函数一样内联?

地图的 std::for_each() 给出无效的初始化错误

std::for_each 和 std::vector 析构函数调用

在lambda中使用静态方法时出错

错误:不匹配的类型:<function> 和 <lambda>