2011-04-29 14 views
7

Admito que tuve dificultades para encontrar una descripción razonable para esto. No puedo pensar en un buen término que describa exactamente lo que estoy buscando. Quizás esto podría llamarse iterador de corte.Iterador "apuntando" a un miembro de un objeto

Digamos que tengo algo como esto:

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

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

Lo que estoy buscando es una manera de construir un iterador, que apunte a un miembro de S. Me gustaría poder pasarlo a algo como std::min_element sin crear un predicado en cada caso. Algo que podría tener este aspecto:

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

¿Hay algún truco plantilla que podría utilizar para lograr esto? ¿O tal vez ya se ha hecho en algún lugar de Boost o en alguna otra biblioteca?

+0

¿No es puntero a miembro lo que quieres? –

+0

¿Cuál sería el resultado deseado al llamar a este 'min_element'? ¿Va a ser un iterador que desreferencia al '' flotante '' mínimo, o el iterador que desreferencia al 'S' que contiene el' S :: f' mínimo? – Cubbi

+0

Sería otro 'slicing_iterator' que apunta al elemento con la' f' más pequeña. No puede ser otra cosa, ya que la única forma de iterar la secuencia es '++' los iteradores dados. – detunized

Respuesta

13

Si usted está buscando un iterador que se convierte en su S S :: f, esto sin duda podría hacerse utilizando impulso (lo que no puede ser?):

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'; 

prueba: https://ideone.com/jgcHr

Pero si está buscando la S cuya S :: f es la más pequeña del vector, el predicado es el enfoque más razonable.

+0

Esto se ve bien. – detunized

2

Si no desea crear una función de predicado para cada caso, le sugiero que no busque un operador de división, sino que implemente su predicado como una función lambda (ya sea usando Boost o C++ 0x). Aquí se dará una explicación detallada

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

(esto es sobre std::sort, pero la comparación en std::min_element funciona igualmente.)

2

Will algo como esto hacer el trabajo?

#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

Esto se ve muy bien también. Y no Boost. Gracias. – detunized

2

Además de lo que ya se le ha sugerido que puede hacerlo casi exactamente igual que el ejemplo de código hace.

Ejemplo:

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; 
} 

Al principio no me di cuenta - se ve similar a lo que sugirió @Stuart Golodetz pero la ventaja es que el operador < no tiene que definirse para el tipo de iterador (por ejemplo, enfermedad de transmisión sexual :: list :: iterador). Hace que esta implementación sea universal.

Cuestiones relacionadas