2010-04-16 105 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的用途 - 它需要一個謂詞來比較元素。