Pregunta

Quiero crear una función que puede tomar diferentes tipos de iteradores que almacenan el mismo tipo de objeto:
La primera es una que contiene std::map shared_ptr<Foo> (typedef-ed como FooMap) y el otro es un std::list que también contiene shared_ptr<Foo> (FooList).

A mi me gusta los MSalters solución sugerida para una pregunta similar y trataron de implementar iteradores boost::variant , que la función obtendrá como parámetros para iterar desde la primera a la segunda.

Mi función es el siguiente (simplificado un poco):

set<Foo> CMyClass::GetUniqueFoos(FooIterator itBegin, FooIterator itEnd)
{
    set<Foo> uniques;
    for(/**/;
        apply_visitor(do_compare(), itBegin, itEnd);  // equals "itBegin != itEnd"
        apply_visitor(do_increment(), itBegin))       // equals "++itBegin"
    {
        // Exact mechanism for determining if unique is omitted for clarity
        uniques.insert( do_dereference< shared_ptr<Foo> >(), itBegin) );
    }

    return uniques;
}

El FooIterator y los visitantes se definen como sigue:

typedef
    boost::variant<
        FooMap::const_iterator,
        FooList::const_iterator>
    FooIterator;

struct do_compare : boost::static_visitor<bool>
{
    bool operator() (
        const FooMap::const_iterator & a,
        const FooMap::const_iterator & b) const
    { return a != b; }

    bool operator() (
        const FooList::const_iterator & a,
        const FooList::const_iterator & b) const
    { return a != b; }
};

struct do_increment: boost::static_visitor<void>
{
    template<typename T>
    void operator()( T& t ) const
    { ++t; }
};

template< typename Reference >
struct do_dereference: boost::static_visitor<Reference>
{
    template<typename T>
    Reference operator()( const T& t ) const
    { return *t; }
};

Tengo la mayor parte del de la fijación de este mail . Esa solución también utiliza adaptadores y políticas, que parece ser un poco demasiado, de acuerdo con la respuesta de MSalters, por lo que no quiere simplemente copiar ese código. Especialmente, ya que sólo entiendo parte de ella.

Con el código anterior me sale el siguiente error del compilador de VS2008 (esto es sólo las primeras líneas de 160 en total, que creo que es un poco demasiado para publicar aquí, pero voy a ser feliz para añadirlos Si alguien quiere verlo todo):

1>c:\boost\boost\variant\detail\apply_visitor_binary.hpp(63) :
 error C2664: 'bool CMyClass::do_compare::operator ()(
 const std::list<_Ty>::_Const_iterator<_Secure_validation> &,
 const std::list<_Ty>::_Const_iterator<_Secure_validation> &) const' :
 cannot convert parameter 1 from 'T0' to
 'const std::list<_Ty>::_Const_iterator<_Secure_validation> &'
1>        with
1>        [
1>            _Ty=shared_ptr<Foo>,
1>            _Secure_validation=true
1>        ]
1>        Reason: cannot convert from 'T0' to 'const std::list<_Ty>::_Const_iterator<_Secure_validation>'
1>        with
1>        [
1>            _Ty=shared_ptr<Foo>,
1>            _Secure_validation=true
1>        ]
1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>        c:\boost\boost\variant\variant.hpp(806) : see reference to function template instantiation 'bool boost::detail::variant::apply_visitor_binary_invoke<Visitor,Value1>::operator ()<T>(Value2 &)' being compiled
1>        with
1>        [
1>            Visitor=const CMyClass::do_compare,
1>            Value1=T0,
1>            T=T1,
1>            Value2=T1
1>        ]
[...]

¿Qué estoy haciendo mal?

¿Fue útil?

Solución

Sospecho casos se echa en falta en su static_visitor do_compare. Recuerde, las variantes podría tener cualquier cosa, por lo que necesita todas las combinaciones posibles, como comparar un FooList :: const_iterator a un FooMap :: const_iterator. Que se queja porque el compilador está tratando de encontrar alguna coincidencia con ese caso, y no se puede convertir un FooMap :: const_iterator a un FooList :: const_iterator.

martilleo a cabo:

struct do_compare : boost::static_visitor<bool>
{
    bool operator() (
        const FooMap::const_iterator & a,
        const FooMap::const_iterator & b) const
    { return a != b; }

    bool operator() (
        const FooList::const_iterator & a,
        const FooList::const_iterator & b) const
    { return a != b; }

    bool operator() (
        const FooMap::const_iterator & a,
        const FooList::const_iterator & b) const
    { return false; }

    bool operator() (
        const FooList::const_iterator & a,
        const FooMap::const_iterator & b) const
    { return false; }
};

Aquí hay una versión con plantillas:

template <typename A, typename B>
bool operator() (
    const A & a,
    const B & b) const
{ return false; }

template <typename A>
bool operator() (
    const A & a,
    const A & b) const
{ return a != b; }

Es la compilación de Comeau, pero no estoy 100% que va a trabajar, por lo que se requiere alguna prueba. Aparte de código más limpio, más versátil, no debería tener ningún efecto, siempre y cuando funciona.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top