2009-11-13 67 views
3

在地图中的第二个值搜索地图的价值,我使用的财产以后这样的:我怎样才能找到使用粘合剂只

typedef std::map<int, int> CMyList; 
static CMyList myList; 

template<class t> struct second_equal 
{ 
    typename typedef t::mapped_type mapped_type; 
    typename typedef t::value_type value_type; 

    second_equal(mapped_type f) : v(f) {}; 
    bool operator()(const value_type &a) { return a.second == v;}; 

    mapped_type v; 
}; 
...  
int i = 7; 
CMyList::iterator it = std::find_if(myList.begin(), myList.end(), 
            second_equal<CMyList>(i)); 

问:我怎样才能在单行做这样的发现没有提供自己写的模板?

回答

8

使用选择器从您从地图获取的value_type中选择第一个或第二个元素。 使用活页夹将值(i)绑定到std::equal_to函数的其中一个参数。 使用作曲家将选择器的输出用作equal_to函数的另一个参数。

//stl version 
CMyList::iterator it = std::find_if(
    myList.begin(), 
    myList.end(), 
    std::compose1(
     std::bind2nd(equal_to<CMyList::mapped_type>(), i), 
     std::select2nd<CMyList::value_type>())) ; 

//Boost.Lambda or Boost.Bind version 
CMyList::iterator it = std::find_if(
    myList.begin(), 
    myList.end(), 
    bind(&CMyList::mapped_type::second, _1)==i); 
+0

是否有可能使用boost :: bind来缩短这一点? – 2009-11-13 12:24:27

+1

现货上,但如此难以阅读和杂乱我建议在代码审查代码清理。增强粘合剂有没有更好的方法? – 2009-11-13 12:25:08

+0

+1,这么多可读与提升:) – 2009-11-13 12:37:32

0

我要离开,自愿。 lambda的问题在于(除了C++ 0x),目前你实际上不能使用类似_.second之类的东西。

就个人而言,我这样使用:

template <class Second> 
class CompareSecond 
{ 
public: 
    CompareSecond(Second const& t) : m_ref(t) {} // actual impl use Boost.callparams 
    template <class First> 
    bool operator()(std::pair<First,Second> const& p) const { return p.second == m_ref; } 
private: 
    Second const& m_ref; 
}; 

我与结合:

template <class Second> 
CompareSecond<Second> compare_second(Second const& t) 
{ 
    return CompareSecond<Second>(t); 
} 

为了得到自动类型推演。

而且这样我可以只写

CMyList::iterator it = std::find_if(myList.begin(), myList.end(), compare_second(i)); 

真实的,它不使用粘合剂。

但至少,我的可读性和易于理解,在我看来,这打败了聪明的欺骗。

注意
其实我去尽可能包裹STL的算法,以充分的容器,所以这将是:

CMyList::iterator it = toolbox::find_if(myList, compare_second(i)); 

其中(恕我直言)是清楚的读出来,你可以在没有得到auto类型推断的关键字。

+0

我喜欢这个笔记。我有一个名为'container.h'的头文件,它在一个单独的命名空间中调用大多数算法,你猜对了'container'。 – 2009-11-13 12:37:23

0

您可以使用Boost Lambda

CMyList::iterator it = std::find_if(
     myList.begin(), myList.end(), 
     boost::lambda::bind(&CMyList::value_type::second, boost::lambda::_1) == i); 
-1

您可以扭转这个问题,只写自己的算法,并用它来代替。这样你就不会写很多小函数。

template <typename Iter, typename T> 
Iter find_second(Iter first, Iter last, T value) { 
    while (first != last) { 
     if (first->second == value) { 
      return first; 
     } 
     ++first; 
    } 
    return first; 
} 

注意这不是测试,甚至编译。

在我看来,解决这个与粘合剂只是要求许多丑陋的代码。你真正要求的是一种新算法,所以只需添加算法即可。有了这个说法,我可能会最终实现像Matthieu M.想出的东西。

+1

我不同意这种方法,但是您为算法选择的名称非常具有误导性。如果我没有看源代码,我会猜测它返回值的第二个匹配。 – 2009-11-13 12:46:51

+0

@daniel:当我命名它时,甚至没有想到......它看起来有点像应该模仿'find_first'的东西。 – 2009-11-13 12:49:09