2011-04-29 82 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建议,但优点是操作<不具有迭代器类型进行定义(如性病::目录::迭代器)。它使这个实现具有普遍性。