2013-05-13 41 views
0

我需要查找地圖中呈現的矢量元素。難題在於該向量由結構組成,所以您應該首先調用成員函數來從結構中提取值,以將其與地圖元素進行比較。查找地圖中呈現的矢量元素

因此,與循環這是很容易:

vector<A>::iterator it; 
for(it = vec.begin(); it != vec.end(); ++it) 
{ 
    if(mp.count(it->getKey())) 
    { 
     break; 
    } 
} 

我的問題:有沒有辦法做到這一點的一條線,像

//this doesn't work as count accepts key_type 
vector<A>::iterator it = find_if(vec.begin(), vec.end(), boost::bind(&map<string, string>::count, mp, boost::bind(&A::getKey, _1))) != 0); 

完整的示例,來測試

#include <string> 
#include <vector> 
#include <iostream> 
#include <algorithm> 

#include <boost/bind.hpp> 
#include <boost/assign.hpp> 

using namespace std; 

class A{ 
public: 
    A(const std::string& key) 
    : key(key) {} 

    std::string getKey(){ return key; } 
private: 
    std::string key; 
}; 

int main(int argc, const char *argv[]) { 

    map<string, string> mp = boost::assign::map_list_of("Key1", "Val1") ("Key2", "Val2") ("Key3", "Val3"); 
    vector<A> vec = boost::assign::list_of("AAA") ("Key2") ("BBB"); 

// vector<A>::iterator it = find_if(vec.begin(), vec.end(), boost::bind(&map<string, string>::count, mp, boost::bind(&A::getKey, _1))) != 0); 
    vector<A>::iterator it; 
    for(it = vec.begin(); it != vec.end(); ++it) 
    { 
     if(mp.count(it->getKey())) 
     { 
      break; 
     } 
    } 

    cout << (it != vec.end() ? "found" : "not found") << endl; 

    return 0; 
} 

在此先感謝

回答

1

您的解決方案很接近,只有一個右括號太多。配售每個括號上換行與縮進各等級強調無效的括號:

vector<A>::iterator it = find_if 
(
    vec.begin(), vec.end(), boost::bind 
    (
    &map<string, string>::count, &mp, boost::bind 
    ( 
     &A::getKey, _1 
    ) 
) 
) // one too many 
!= 0); 

最簡單的形式,該行成爲iterator = find_if(...) != 0),這將導致編譯失敗在任:

  • 不能夠找到operator!=(iterator, int)
  • )令牌!= 0)

使用正確的圓括號,!= 0使用由boost::bind提供的運算符超負荷。該生產線將如下所示:

vector<A>::iterator it = find_if(vec.begin(), vec.end(), 
    boost::bind(&map<string, string>::count, &mp, 
       boost::bind(&A::getKey, _1)) != 0); 

然而,考慮這樣一個簡單的操作的可讀性。如果一個簡單的for循環不是通用的,可重用的就夠了,然後再考慮一個便利函數內隱藏它:

template <typename InputIterator, 
      typename C, 
      typename Fn> 
InputIterator find_if_contains(
    InputIterator first, 
    InputIterator last, 
    const C& container, 
    Fn fn) 
{ 
    while (first != last) 
    { 
    if (0 != container.count(fn(*first))) return first; 
    ++first; 
    } 
    return last; 
} 

... 

vector<A>::iterator it = find_if_contains(
    vec.begin(), vec.end(), 
    mp, boost::bind(&A::getKey, _1) 
); 

否則,自定義斷言類型可以提高可讀性而對於不同類型的再利用提供一些額外的靈活性。例如,請考慮以下適用於各種關聯容器的謂詞類型:

template <typename C, 
      typename Fn> 
struct contains_predicate 
{ 
    contains_predicate(const C& container, Fn fn) 
    : container_(&container), fn_(fn) 
    {} 

    template <typename T> 
    bool operator()(T& t) 
    { 
    return 0 != container_->count(fn_(t)); 
    } 

    const C* container_; 
    Fn fn_; 
}; 

template <typename C, 
      typename Fn> 
contains_predicate<C, Fn> 
contains(const C& container, Fn fn) 
{ 
    return contains_predicate<C, Fn>(container, fn); 
} 

... 

vector<A>::iterator it = find_if(vec.begin(), vec.end(), 
    contains(mp, boost::bind(&A::getKey, _1))); 
+0

嗨,這個工程。我相信問題不在於大括號的數量,而在...&mp ...我錯過了&。 – Alex 2013-05-14 11:58:54

+0

@亞歷克斯:很高興它適合你。通過值而不是指針傳遞'mp'只是一種優化,因爲'mp'可以被複制。問題是額外的括號。 [這](http://coliru.stacked-crooked.com/view?id = b2a625da792e0c3b7e7b203b9053ca65-7063104e283ed82d51a6fde7370c6e59)在線編譯器失敗,因爲它無法找到運算符!=採用迭代器(從find_if返回)和int(0)。刪除多餘的括號會導致'!= 0'使用'boost :: bind'運算符重載,而不是試圖與'find_if'的返回值進行比較。 – 2013-05-14 12:38:54

0

在C++ 11,使用lambda:

find_if(vec.begin(), vec.end(), [&](A const & a){return mp.count(a.getKey());}); 

但由於您使用的Boost.Assign而不是統一的初始化,也許你不能這樣做。恐怕我不知道如何使用bind來構建一個仿函數。

+0

我希望我可以。不過,我正在使用以前版本的C++。 – Alex 2013-05-13 15:02:45

+0

@Alex:在這種情況下,我會堅持使用'for'循環。即使你確實找到了合適的'bind'表達式,它的可讀性也會小得多。 – 2013-05-13 15:04:12