在 std::vector<std::string> 上使用 find_if 和 bind2nd 和 string::compare

Posted

技术标签:

【中文标题】在 std::vector<std::string> 上使用 find_if 和 bind2nd 和 string::compare【英文标题】:Using find_if on std::vector<std::string> with bind2nd and string::compare 【发布时间】:2009-09-04 12:13:49 【问题描述】:

这似乎是一个学术问题,但我仍然会对答案非常感兴趣:

我有一个字符串向量s,我想在其中找到给定的字符串findme。这可以使用类似的东西来完成

find(s.begin(), s.end(), findme);

我的问题是:一定有一种方法可以使用 STL 字符串的 find_ifcompare 方法作为谓词,但是如何做呢?类似的东西

find_if(s.begin(), s.end(), bind2nd(mem_fun_ref(&string::compare), string("findme")) );

不起作用,因为 compare 方法有几个重载,编译器不知道选择哪一个。

作为第二步:我使用 find_if 而不是 find 的动机是,我有一个从具有字符串属性 name 的类派生的对象向量,并且我想查找具有给定名称的对象。这可能吗(无需编写额外的函数用作谓词)?


编辑:正如使用 Boost 提到的一些(大多数:) 答案——我不希望为此包含 Boost。 (据我所知,大多数 Boost 库都是“唯一”模板,所以应该有不使用 Boost 的方法。)

【问题讨论】:

不是您正在寻找的答案,但对我来说,这就是我划清界限的地方。如果很难设置绑定方案,那么当它不完全符合您的预期时,通常很难对其进行调试。说了这么多,你有没有考虑过 boost::bind 和 boost::lambda? 【参考方案1】:

一种选择是将成员函数指针转换为合适的类型。您忘记的另一件事是 std::string::compare 为相等的字符串返回 0,因此您还需要取反函子。总而言之:

std::find_if(
    vec.begin(), vec.end(),
    std::not1(
        std::bind2nd(
            std::mem_fun_ref(static_cast<int (std::string::*)(const char*)const>(&std::string::compare)),
            "findme"
        )
    )
);

关于您反对 boost 的理由:它的模板比您在 STL 功能标头中找到的模板灵活一个数量级。要么是提升,要么等待 C++0x lambdas(我相信在这种情况下这将是更可取的方式),要么你自己编写一些帮助程序。目前它不能比以下更简单:

std::find_if(vec.begin(), vec.end(), boost::bind(&X::name, _1) == "findme");

仅供参考,C++0x 将添加类似于 boost::bind 的 std::bind,但似乎重载 operator== 的便利性将不存在。

【讨论】:

这不能编译!参考参考问题。 对,不使用 VC++(对于 MinGW 和 Comeau 在线来说可以)。我改为使用不应该出现相同问题的不同重载。 (我想这个问题实际上是关于在重载之前要做什么,而不是具体如何使用 find_if 和 string::compare 查找字符串 - 这很愚蠢,应该很清楚。) 还有一点,重载的存在对于 boost::bind 等来说同样是个问题,除非碰巧有另一种方式(例如在这种情况下,使用 operator== 而不是比较)。【参考方案2】:

自己选择正确的重载。

int (string::*compare)(const string&) const;
compare = &string::compare;
find_if(s.begin(), s.end(), bind2nd( mem_fun_ref(compare), string("findme")));

但是你会被引用问题“有效 STL 的第 50 项”的引用所困扰。 而 boost.Bind 库或 boost.Lambda 就是解决方案。

int (string::*compare)(const string&) const;
compare = &string::compare;
find_if(s.begin(), s.end(), bind(compare, _1, "findme")==0);

或者

find_if(s.begin(), s.end(), bind2nd(std::equal_to<string>(), string("findme")));

【讨论】:

最后一个版本是所有这些答案中最干净、最易读的版本。难怪它没有得到任何选票;)【参考方案3】:

如果函数具有重载函数,您可以将函数强制转换为正确的签名,例如 (void (*)(int,int))(&amp;f).

对于你的第二个问题,如果你使用boost,你可以这样做,

find_if(s.begin(), s.end(), boost::bind(std::equal_to<string>(), boost::bind(&SomeClass::name, _1), name);

【讨论】:

boost::bind 为方便起见重载了一些运算符,因此可以使用 operator== 替换示例中的“equal_to”par: boost::bind(&SomeClass::name, _1) = = 更具可读性的名称 我以为那只是在 boost::lambda 中。我同意在这种情况下它更具可读性,但我只是想演示如何使用 boost::bind boost::bind 的原始版本没有这些运算符重载,但“最近”(从 1.33 开始)版本有:boost.org/doc/libs/1_40_0/libs/bind/bind.html#operators【参考方案4】:

我想你会发现如果你试图一起调用几个函数,语法很快就会变得笨拙。你尝试过这样的事情吗?

find_if(s.begin(), s.end(), bind2nd(mem_fun_ref(&string::compare), "findme"));

这与char * 重载不匹配吗?

【讨论】:

问题出在mem_fun_ref(&amp;string::compare)这个表达式上。如何将函数重载集传递给mem_fun_ref

以上是关于在 std::vector<std::string> 上使用 find_if 和 bind2nd 和 string::compare的主要内容,如果未能解决你的问题,请参考以下文章

std::vector<std::array<T, N>> 或 std::array<std::vector<T>,N> 类型的数组如何存储在内存中?

如何在 C++17 中将 std::string 转换为 std::vector<std::byte>?

在 std::vector<T> 和 std::vector<unique_ptr<T>> 上均匀迭代

从 std::vector<std::vector<float>> 转换为 float**

在现代 C++ 中将 std::array<std::array<T,N>> 转换为 std::vector<T>

如何桥接 JavaScript(参差不齐)数组和 std::vector<std::vector<T>> 对象?