2011-04-29 83 views
7

我承認我很難爲此提出合理的描述。我想不出一個能夠準確描述我要找的東西的好名詞。也許這可以稱爲切片迭代器迭代器「指向」對象的成員

比方說,我有這樣的事情:

struct S 
{ 
    int i; 
    char *s; 
    float f; 
}; 

std::vector<S> v(10); 

我正在尋找一種方法來構建一個迭代器,這將指向的S成員。我希望能夠將它傳遞給std::min_element之類的東西,而無需在每種情況下創建謂詞。東西可能看起來像這樣:

std::min_element(slicing_iterator(v.begin(), S::f), slicing_iterator(v.end(), S::f)); 

是否有任何模板技巧,我可以用來實現這一目標?或者也許它已經在Boost或其他庫中的某個地方完成了?

+0

不是指向成員什麼你想要的? – 2011-04-29 10:52:37

+0

調用這個'min_element'的結果是什麼?它是否會成爲一個迭代器,對最小的'float'進行解引用,或者對包含最小'S :: f'的'S'進行解引用的迭代器? – Cubbi 2011-04-29 11:03:06

+0

這將是另一個'slicing_iterator'指向具有最小'f'的元素。它不能成爲其他任何東西,因爲迭代序列的唯一方法是'++'給定的迭代器。 – detunized 2011-04-29 11:05:30

回答

13

如果你正在尋找一個轉化s轉換它的s :: F側迭代器,這當然可以使用boost(有什麼不可以?)來完成:

std::cout << *std::min_element(
       boost::make_transform_iterator(v.begin(), boost::bind(&S::f, _1)), 
       boost::make_transform_iterator(v.end(), boost::bind(&S::f, _1)) 
      ) << '\n'; 

測試:https://ideone.com/jgcHr

但是,如果你正在尋找S :: f是向量中最小的S,謂詞是最合理的方法。

+0

這看起來不錯。 – detunized 2011-04-29 11:09:47

2

如果您不想爲每種情況創建一個謂詞函數,我會建議您不要查找切片運算符,而是將您的謂詞作爲lambda函數(使用Boost或C++ 0x)來實現。在這裏,你會發現一個詳細的解釋

http://www.codeproject.com/KB/cpp/Sort.aspx

(這是關於std::sort,但在std::min_element作品同樣進行比較)。

2

請問像這樣做的工作?

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

struct S 
{ 
    int i; 
    float f; 

    S() : i(0), f(0.0f) {} 
    S(int i_, float f_) : i(i_), f(f_) {} 
}; 

template <typename Iterator, typename T, typename M> 
class SlicingIterator : public std::iterator<typename Iterator::iterator_category,M> 
{ 
private: 
    Iterator m_it; 
    M T::*m_m; 
public: 
    SlicingIterator(const Iterator& it, M T::*m) 
    : m_it(it), m_m(m) 
    {} 

    const M operator*() const 
    { 
     return (*m_it).*m_m; 
    } 

    bool operator!=(const SlicingIterator& rhs) const 
    { 
     return m_it != rhs.m_it; 
    } 

    SlicingIterator& operator++() 
    { 
     ++m_it; 
     return *this; 
    } 

    bool operator<(const SlicingIterator& rhs) const 
    { 
     return m_it < rhs.m_it; 
    } 
}; 

template <typename Iterator, typename T, typename M> 
SlicingIterator<Iterator,T,M> slicing_iterator(const Iterator& it, M T::*m) 
{ 
    return SlicingIterator<Iterator,T,M>(it, m); 
} 

int main() 
{ 
    std::vector<S> vec; 
    vec.push_back(S(23,9)); 
    vec.push_back(S(17,10)); 
    std::copy(slicing_iterator(vec.begin(), &S::f), slicing_iterator(vec.end(), &S::f), std::ostream_iterator<float>(std::cout, " ")); 
    return 0; 
} 
+0

這看起來也很好。並沒有提升。謝謝。 – detunized 2011-04-29 11:32:12

2

除了已經建議的內容之外,您可能會做的與您的代碼示例幾乎完全相同。

例子:

template< class IterT, class ObjT, class MemberT > 
class slicing_iterator; 

template< class IterT, class ObjT, class MemberT > 
inline bool operator==(
        const slicing_iterator<IterT,ObjT,MemberT>& a, 
        const slicing_iterator<IterT,ObjT,MemberT>& b 
       ); 

template< class IterT, class ObjT, class MemberT > 
inline bool operator!=(
        const slicing_iterator<IterT,ObjT,MemberT>& a, 
        const slicing_iterator<IterT,ObjT,MemberT>& b 
       ); 

template< class IterT, class ObjT, class MemberT > 
class slicing_iterator 
{ 
    IterT m_iter; 
    MemberT ObjT::* m_member; 

public: 
    slicing_iterator(IterT iter, MemberT ObjT::*member) : 
     m_iter(iter), m_member(member) 
    { 
    } 

    slicing_iterator& operator++() { ++m_iter; return *this; } 
    slicing_iterator& operator--() { --m_iter; return *this; } 

    MemberT& operator*() { return static_cast<ObjT&>(*m_iter).*m_member; } 
    const MemberT& operator*() const { return static_cast<const ObjT&>(*m_iter).*m_member; } 

    MemberT* operator->() { return &m_iter->*m_member; } 
    const MemberT* operator->() const { return &m_iter->*m_member; } 

private: 
    friend bool operator== <IterT,ObjT,MemberT>(
         const slicing_iterator<IterT,ObjT,MemberT>& a, 
         const slicing_iterator<IterT,ObjT,MemberT>& b 
        ); 
    friend bool operator!= <IterT,ObjT,MemberT>(
         const slicing_iterator<IterT,ObjT,MemberT>& a, 
         const slicing_iterator<IterT,ObjT,MemberT>& b 
        ); 
}; 

template< class IterT, class ObjT, class MemberT > 
inline bool operator==(
        const slicing_iterator<IterT,ObjT,MemberT>& a, 
        const slicing_iterator<IterT,ObjT,MemberT>& b 
       ) 
{ 
    return a.m_iter == b.m_iter && a.m_member == a.m_member; 
} 

template< class IterT, class ObjT, class MemberT > 
inline bool operator!=(
        const slicing_iterator<IterT,ObjT,MemberT>& a, 
        const slicing_iterator<IterT,ObjT,MemberT>& b 
       ) 
{ 
    return a.m_iter != b.m_iter || a.m_member != a.m_member; 
} 

template< class IterT, class ObjT, class MemberT > 
inline slicing_iterator<IterT,ObjT,MemberT> 
make_slicing_iterator(IterT iter, MemberT ObjT::*member) 
{ 
    return slicing_iterator<IterT,ObjT,MemberT>(iter, member); 
} 

struct S 
{ 
    int i; 
    char *s; 
    float f; 
}; 

int main(void) 
{ 
    std::vector<S> v(10); 

    std::min_element(
      make_slicing_iterator(v.begin(), &S::f), 
      make_slicing_iterator(v.end(), &S::f) 
      ); 
    return 0; 
} 

起初我沒有注意到 - 它看起來類似於@Stuart Golodetz建議,但優點是操作<不具有迭代器類型進行定義(如性病::目錄::迭代器)。它使這個實現具有普遍性。