2013-05-13 38 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