如何使用比较对象进行std :: find?

8

我对std::find函数的接口感到困惑。为什么它不接受一个Compare对象,告诉它如何比较两个对象?

如果我可以传递一个Compare对象,我就可以使下面的代码工作,我希望通过值进行比较,而不仅仅是直接比较指针值:

typedef std::vector<std::string*> Vec;
Vec vec;
std::string* s1 = new std::string("foo");
std::string* s2 = new std::string("foo");
vec.push_back(s1);
Vec::const_iterator found = std::find(vec.begin(), vec.end(), s2);
// not found, obviously, because I can't tell it to compare by value
delete s1;
delete s2;

以下是建议的操作方式吗?
template<class T>
struct MyEqualsByVal {
  const T& x_;
  MyEqualsByVal(const T& x) : x_(x) {}
  bool operator()(const T& y) const {
    return *x_ == *y;
  }
};
// ...
vec.push_back(s1);
Vec::const_iterator found = 
    std::find_if(vec.begin(), vec.end(),
                 MyEqualsByVal<std::string*>(s2)); // OK, will find "foo"
3个回答

8
find无法重载以使用一元谓词而不是值,因为它是一个未受限制的模板参数。因此,如果您调用find(first, last, my_predicate),则可能存在歧义,即您想要在范围的每个成员上评估谓词,还是您想要查找与谓词本身相等的范围成员(对于标准库设计人员来说,它可能是一系列谓词,或者迭代器的value_type既可以转换为谓词类型,也可以转换为其argument_type)。因此需要find_if使用单独的名称。 find本可以重载以接受可选的二元谓词,除了要搜索的值之外。但是,像您所做的那样,在函数对象中捕获值是一种如此标准的技术,以至于我认为这不会带来巨大的收益:它肯定从来都不是必需的,因为您始终可以使用find_if实现相同的结果。
如果您得到了想要的find,则仍然必须编写一个函数对象(或使用boost),因为<functional>中没有包含任何解引用指针的内容。您的函数对象作为二元谓词会更简单一些,或者您可以使用函数指针,因此它将是一个适度的收益。因此,我不知道为什么没有提供这个功能。鉴于copy_if的惨败,我不确定假设总有好的算法可用是否有太多价值 :-)

1
@dehmann:唯一的问题是它不在标准中。它基本上是由于编辑错误而被遗漏了。 - Steve Jessop

2

由于您的 T 是指针,因此在函数对象中存储指针的副本也是一个不错的选择。

除此之外,就是这样做了,没有太多需要注意的地方。

顺便提一下,将裸指针存储在容器中并不是一个好主意,除非您非常小心地确保异常安全性,否则这几乎总是比它所值得的更麻烦。


而且...我完全错过了问题的前半部分...哎呀。不过,Steve Jessop的答案比我能解释的还要好。 - James McNellis

0

这正是find_if的用途 - 它接受一个谓词,用于比较元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接