«Невозможно преобразовать параметр» с помощью итератора boost :: variable - PullRequest
3 голосов
/ 09 июня 2009

Я хочу создать функцию, которая может принимать разные типы итераторов, в которых хранится один и тот же тип объекта:
Первый - это std::map, содержащий shared_ptr<Foo> (typedef-ed как FooMap), а другой - std::list, который также содержит shared_ptr<Foo> (FooList).

Мне действительно нравится решение, которое MSalters предложило для аналогичного вопроса и попыталось реализовать boost::variant итераторов, которые функция получит в качестве параметров для перебора от первого до второго.

Моя функция выглядит следующим образом (немного упрощена):

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

FooIterator и посетители определяются следующим образом:

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

Я получил большинство из вышеперечисленных из приложения к этому письму . Это решение также использует адаптеры и политики, которые, по мнению MSalters, кажутся слишком большими, поэтому я не хочу просто копировать этот код. Тем более, что я понимаю только часть этого.

С помощью приведенного выше кода я получаю следующую ошибку компилятора из VS2008 (это всего лишь первые несколько строк из 160, что, я думаю, слишком много для публикации здесь; однако я буду рад их добавить, если кто-то хочет все это увидеть):

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>        ]
[...]

Что я делаю не так?

1 Ответ

6 голосов
/ 09 июня 2009

Я подозреваю, что в вашем do_compare static_visitor отсутствуют случаи. Помните, что варианты могут иметь что угодно, поэтому вам нужны все возможные комбинации, например, сравнение FooList :: const_iterator с FooMap :: const_iterator. Он жалуется, потому что компилятор пытается найти какое-то соответствие для этого случая и не может преобразовать FooMap :: const_iterator в FooList :: const_iterator.

Стучит:

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

Вот версия с шаблонами:

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

Он компилируется на comeau, но я не на 100% это сработает, поэтому требуется некоторое тестирование. Помимо чистого, более универсального кода, он не должен иметь никакого эффекта, пока он работает.

...