Boost phoenix 或 lambda 库问题:从 std::vector 中删除元素

发布于 2024-07-06 17:11:32 字数 779 浏览 9 评论 0原文

我最近遇到了一个问题,我认为 boost::lambda 或 boost::phoenix 可以帮助解决,但我无法获得正确的语法,所以我用了另一种方式。 我想要做的是删除“字符串”中小于一定长度且不在另一个容器中的所有元素。

这是我的第一次尝试:

std::vector<std::string> strings = getstrings();
std::set<std::string> others = getothers();
strings.erase(std::remove_if(strings.begin(), strings.end(), (_1.length() < 24 &&  others.find(_1) == others.end())), strings.end());

我最终的做法是这样的:

struct Discard
{
    bool operator()(std::set<std::string> &cont, const std::string &s)
    {
        return cont.find(s) == cont.end() && s.length() < 24;
    }
};

lines.erase(std::remove_if( lines.begin(), lines.end(), boost::bind<bool>(Discard(), old_samples, _1)), lines.end());

I recently ran into a problem that I thought boost::lambda or boost::phoenix could help be solve, but I was not able to get the syntax right and so I did it another way. What I wanted to do was remove all the elements in "strings" that were less than a certain length and not in another container.

This is my first try:

std::vector<std::string> strings = getstrings();
std::set<std::string> others = getothers();
strings.erase(std::remove_if(strings.begin(), strings.end(), (_1.length() < 24 &&  others.find(_1) == others.end())), strings.end());

How I ended up doing it was this:

struct Discard
{
    bool operator()(std::set<std::string> &cont, const std::string &s)
    {
        return cont.find(s) == cont.end() && s.length() < 24;
    }
};

lines.erase(std::remove_if( lines.begin(), lines.end(), boost::bind<bool>(Discard(), old_samples, _1)), lines.end());

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沫尐诺 2024-07-13 17:11:32

您需要 boost::labmda::bind 来调用 lambda-ify 函数,例如长度 < 24 部分变为:

bind(&string::length, _1) < 24

编辑

请参阅“Head Geek”的帖子了解为什么 set::find 很棘手。 他得到它来解决正确的 set::find 重载(所以我复制了该部分),但他错过了一个重要的 boost::ref() ——这就是为什么与 end() 的比较总是失败(容器被复制) 。

int main()
{
  vector<string> strings = getstrings();
  set<string> others = getothers();
  set<string>::const_iterator (set<string>::*findFn)(const std::string&) const = &set<string>::find;
  strings.erase(
    remove_if(strings.begin(), strings.end(),
        bind(&string::length, _1) < 24 &&
        bind(findFn, boost::ref(others), _1) == others.end()
      ), strings.end());
  copy(strings.begin(), strings.end(), ostream_iterator<string>(cout, ", "));
  return 0;
}

You need boost::labmda::bind to lambda-ify function calls, for example the length < 24 part becomes:

bind(&string::length, _1) < 24

EDIT

See "Head Geek"'s post for why set::find is tricky. He got it to resolve the correct set::find overload (so I copied that part), but he missed an essential boost::ref() -- which is why the comparison with end() always failed (the container was copied).

int main()
{
  vector<string> strings = getstrings();
  set<string> others = getothers();
  set<string>::const_iterator (set<string>::*findFn)(const std::string&) const = &set<string>::find;
  strings.erase(
    remove_if(strings.begin(), strings.end(),
        bind(&string::length, _1) < 24 &&
        bind(findFn, boost::ref(others), _1) == others.end()
      ), strings.end());
  copy(strings.begin(), strings.end(), ostream_iterator<string>(cout, ", "));
  return 0;
}
御守 2024-07-13 17:11:32

除了 bind 调用(Adam Mitz 在这一部分上是正确的)之外,主要问题是 std::set::find 是一个重载函数,因此您无法直接在 bind 调用中指定它。 您需要告诉编译器要使用哪个 find,如下所示:

using namespace boost::lambda;
typedef std::vector<std::string> T1;
typedef std::set<std::string> T2;

T1 strings = getstrings();
T2 others = getothers();

T2::const_iterator (T2::*findFn)(const std::string&) const=&T2::find;
T2::const_iterator othersEnd=others.end();

strings.erase(std::remove_if(strings.begin(), strings.end(),
    (bind(&std::string::length, _1) < 24
        && bind(findFn, boost::ref(others), _1) == othersEnd)),
    strings.end());

可以编译,但无法正常工作,原因我还没有弄清楚。 find 函数永远不会返回 others.end(),因此它永远不会删除任何内容。 仍在研究那部分。

编辑:更正,find 函数 返回others.end(),但比较无法识别它。 我不知道为什么。

后来编辑:感谢 Adam 的评论,我看到出了什么问题,并纠正了问题。 现在它按预期工作。

(如果您想查看我的完整测试程序,请查看编辑历史记录。)

The main problem, other than the bind calls (Adam Mitz was correct on that part), is that std::set<std::string>::find is an overloaded function, so you can't specify it directly in the bind call. You need to tell the compiler which find to use, like so:

using namespace boost::lambda;
typedef std::vector<std::string> T1;
typedef std::set<std::string> T2;

T1 strings = getstrings();
T2 others = getothers();

T2::const_iterator (T2::*findFn)(const std::string&) const=&T2::find;
T2::const_iterator othersEnd=others.end();

strings.erase(std::remove_if(strings.begin(), strings.end(),
    (bind(&std::string::length, _1) < 24
        && bind(findFn, boost::ref(others), _1) == othersEnd)),
    strings.end());

This compiles, but it doesn't work properly, for reasons I haven't yet figured out... the find function is never returning others.end(), so it's never deleting anything. Still working on that part.

EDIT: Correction, the find function is returning others.end(), but the comparison isn't recognizing it. I don't know why.

LATER EDIT: Thanks to Adam's comment, I see what was going wrong, and have corrected the problem. It now works as intended.

(Look at the edit history if you want to see my full test program.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文