2010-04-16 97 views
6

我对std::find的界面感到困惑。为什么不用Compare对象来告诉它如何比较两个对象?如何使用比较对象std :: find?

如果我能通过一个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" 

回答

6

find无法重载以取一个一元谓词而不是一个值,因为它是一个无约束的模板参数。因此,如果您调用find(first, last, my_predicate),那么您是否希望在范围的每个成员上评估谓词,或者是否想要找到与谓词本身相同的范围成员(可能是范围对于标准库的所有设计者而言,它们都知道或关心,或者迭代器的value_type可以转换为谓词类型,也可以转换为其argument_type)。因此需要find_if以独立的名称。

find除了搜索的值之外,可能已被重载以采用可选的二元谓词。但是,正如你所做的那样,在函数中捕获值是一种标准技术,我认为这不会是一个巨大的收益:它肯定没有必要,因为你始终可以通过find_if获得相同的结果。

如果你有你想要的find,你仍然必须编写一个函子(或使用boost),因为<functional>不包含任何内容来取消引用指针。尽管你的函子会比二元谓词简单一点,或者你可以使用函数指针,所以它会是一个小小的增益。所以我不知道为什么没有提供。鉴于copy_if惨败,我不确定有多少价值假设总是有很好的理由,算法不可用:-)

+0

谢谢!出于好奇,“copy_if”有什么问题? – Frank 2010-04-17 02:33:33

+1

@dehmann:唯一错的是它不在标准中。基本上由于编辑事故而被排除在外。 – 2010-04-17 02:34:37

2

由于您的T是一个指针,你可能也存储在函数对象的指针的副本。

除此之外,这是如何完成的,没有什么更多。除此之外,将裸指针存储在容器中并不是一个好主意,除非您非常小心地确保异常安全,而这几乎总是比它的价值更加麻烦。

+0

而且......我完全错过了问题的第一半......哎呀。尽管如此,史蒂夫杰索普的回答比我无论如何都能解释得更好。 – 2010-04-17 00:11:33

0

这正是find_if的用途 - 它需要一个谓词来比较元素。