2009-11-13 33 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