在 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_if
和 compare
方法作为谓词,但是如何做呢?类似的东西
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))(&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(&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**