2016-09-12 3 views
1

Я хотел бы использовать BOOST_FOREACH с одним из старых типов контейнеров в моей базе кода, которые я не могу изменить.Как адаптировать пользовательский тип контейнера к BOOST_FOREACH?

У меня есть следующие методы, определенные на этом типе:

  • .length() возвращающего текущее количество элементов в контейнере
  • .operator[](unsigned i) возвращает ссылку на элемент под индексом i

я знаю что мне нужно, чтобы мой тип контейнера удовлетворял Single Pass Range Concept, поскольку предлагаемая документация по ускорению, но я как-то потерялся, так как не могу изменить тип.

Любые подсказки/решения будут полезны.

EDIT

Я попытался пойти с предложением, но этот код

struct wrapper 
{ 
    struct iterator : std::iterator<std::forward_iterator_tag, ObservationReport> 
    { 
     iterator(ObservationReportList* p, int i) : pnt_(p), i_(i) {} 

     ObservationReport& operator*() { 
      return (*pnt_)[i_]; 
     } 

     iterator& operator++() { 
      ++i_; 
      return *this; 
     } 

     bool operator==(const iterator& r) const { 
      return i_ == r.i_; 
     } 
     bool operator!=(const iterator& r) const { 
      return i_ != r.i_; 
     } 

     ObservationReportList* pnt_; 
     int i_; 
    }; 

    wrapper(ObservationReportList & n) 
    : begin_(boost::addressof(n), 0) 
    , end_(boost::addressof(n), n.length()) 
    {} 

    iterator begin() { return begin_; } 
    iterator end() { return end_; } 

    iterator begin_, end_; 
}; 

// usage 

ObservationReportList reportList; 
// filling reportList 
BOOST_FOREACH(ObservationReport o, wrapper(reportList)) 
{ 
} 

дает мне следующие ошибки компилятора:

In file included from /usr/include/boost159/boost/foreach.hpp:71:0, 
       from test/src/MessageFillerTest.cpp:18: 
/usr/include/boost159/boost/mpl/eval_if.hpp: In instantiation of ‘struct boost::mpl::eval_if<mpl_::bool_<true>, boost::range_const_iterator<wrapper, void>, boost::range_mutable_iterator<wrapper, void> >’: 
/usr/include/boost159/boost/foreach.hpp:359:13: required from ‘struct boost::foreach_detail_::foreach_iterator<wrapper, mpl_::bool_<true> >’ 
/usr/include/boost159/boost/foreach.hpp:679:1: required by substitution of ‘template<class T> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, mpl_::bool_<true> >::type> boost::foreach_detail_::begin(
boost::foreach_detail_::auto_any_t, boost::foreach_detail_::type2type<T, mpl_::bool_<true> >*, bool*) [with T = wrapper]’ 
test/src/MessageFillerTest.cpp:206:3: required from here 
/usr/include/boost159/boost/mpl/eval_if.hpp:38:31: error: no type named ‘type’ in ‘boost::mpl::eval_if<mpl_::bool_<true>, boost::range_const_iterator<wrapper, void>, boost::range_mutable_iterator<wrapper, void> >::f_ {aka struct boost::ran 
ge_const_iterator<wrapper, void>}’ 
    typedef typename f_::type type; 
          ^
In file included from test/src/MessageFillerTest.cpp:18:0: 
test/src/MessageFillerTest.cpp: In member function ‘virtual void MessageFiller_XXX_Test::TestBody()’: 
/usr/include/boost159/boost/foreach.hpp:1020:39: error: no matching function for call to ‘begin(const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<wrapper, mpl_::bool_<true> >*, bool*)’ 
     , BOOST_FOREACH_SHOULD_COPY(COL)) 
            ^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’ 
    if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else  \ 
                      ^
test/src/MessageFillerTest.cpp:206:3: note: in expansion of macro ‘BOOST_FOREACH’ 
    BOOST_FOREACH(ObservationReport o, wrapper(reportList)) 
^
/usr/include/boost159/boost/foreach.hpp:660:1: note: candidate: template<class T, class C> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, C>::type> boost::foreach_detail_::begin(boost::foreach_detail_ 
::auto_any_t, boost::foreach_detail_::type2type<T, C>*, mpl_::true_*) 
begin(auto_any_t col, type2type<T, C> *, boost::mpl::true_ *) // rvalue 
^ 
/usr/include/boost159/boost/foreach.hpp:660:1: note: template argument deduction/substitution failed: 
/usr/include/boost159/boost/foreach.hpp:964:46: note: cannot convert ‘boost::foreach_detail_::should_copy_impl(((mpl_::bool_<false>*)0u), ((mpl_::bool_<false>*)0u), (& _foreach_is_rvalue206))’ (type ‘bool*’) to type ‘mpl_::true_* {aka mp 
l_::bool_<true>*}’ 
    (boost::foreach_detail_::should_copy_impl(             \ 
              ^
/usr/include/boost159/boost/foreach.hpp:1020:9: note: in expansion of macro ‘BOOST_FOREACH_SHOULD_COPY’ 
     , BOOST_FOREACH_SHOULD_COPY(COL)) 
     ^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’ 
    if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else  \ 
                      ^
test/src/MessageFillerTest.cpp:206:3: note: in expansion of macro ‘BOOST_FOREACH’ 
    BOOST_FOREACH(ObservationReport o, wrapper(reportList)) 
^
/usr/include/boost159/boost/foreach.hpp:668:1: note: candidate: template<class T, class C> boost::foreach_detail_::auto_any<typename boost::foreach_detail_::foreach_iterator<T, C>::type> boost::foreach_detail_::begin(boost::foreach_detail_ 
::auto_any_t, boost::foreach_detail_::type2type<T, C>*, mpl_::false_*) 
begin(auto_any_t col, type2type<T, C> *, boost::mpl::false_ *) // lvalue 
^ 
/usr/include/boost159/boost/foreach.hpp:668:1: note: template argument deduction/substitution failed: 
/usr/include/boost159/boost/foreach.hpp:964:46: note: cannot convert ‘boost::foreach_detail_::should_copy_impl(((mpl_::bool_<false>*)0u), ((mpl_::bool_<false>*)0u), (& _foreach_is_rvalue206))’ (type ‘bool*’) to type ‘mpl_::false_* {aka m 
pl_::bool_<false>*}’ 
    (boost::foreach_detail_::should_copy_impl(             \ 
              ^
/usr/include/boost159/boost/foreach.hpp:1020:9: note: in expansion of macro ‘BOOST_FOREACH_SHOULD_COPY’ 
     , BOOST_FOREACH_SHOULD_COPY(COL)) 
     ^
/usr/include/boost159/boost/foreach.hpp:1101:77: note: in expansion of macro ‘BOOST_FOREACH_BEGIN’ 
    if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else  \ 
                      ^
test/src/MessageFillerTest.cpp:206:3: required from here 
/usr/include/boost159/boost/foreach.hpp:768:1: error: no type named ‘type’ in ‘struct boost::foreach_detail_::foreach_reference<wrapper, mpl_::bool_<true> >’ 
+0

обеспечивают начать() и конец(), который возвращает тип итератора. –

+0

Вы можете использовать обертку, которая предоставляет необходимые функции и хранит внутреннюю ссылку на реальный экземпляр вашего контейнера. – Garf365

+0

Вам действительно нужно предоставить дополнительную информацию. Небольшой образец кода был бы хорош. – juanchopanza

ответ

3

Оболочка может обеспечить необходимый интерфейс.

Обратите внимание, что в этом примере оператор [] nasty_thing возвращает ссылку на int в массиве последовательных int.

Это не тот случай, нам нужно сделать работу обертки в терминах индекса.

#include <utility> 
#include <memory> 

// 
// a nasty thing that contains consecutive ints 
struct nasty_thing 
{ 
    int& operator[](int i); 
    int length(); 
}; 

// because we are dealing in consecutive ints, we can approximate an iterator with a pointer 

struct wrapper 
{ 
    using iterator = int*; 

    wrapper(nasty_thing& n) 
    : begin_(std::addressof(n[0])) 
    , end_(begin_ + n.length()) 
    {} 

    iterator begin() const { return begin_; } 
    iterator end() const { return end_; } 

    iterator begin_, end_; 
}; 

extern nasty_thing& nt; 

int main() 
{ 
    // simulate BOOST_FOREACH 
    for (auto& i : wrapper(nt)) 
    { 

    } 
} 

Это версия, в которой nasty_thing не представляет непрерывную память:

#include <utility> 
#include <memory> 
#include <boost/foreach.hpp> 

// 
// a nasty thing that contains consecutive ints 
struct nasty_thing 
{ 
    int& operator[](int i); 
    int length(); 
}; 

struct wrapper 
{ 
    struct iterator : std::iterator<std::forward_iterator_tag, int> 
    { 
     iterator(nasty_thing* p, int i) : pnt_(p), i_(i) {} 
     int& operator*() const { 
      return (*pnt_)[i_]; 
     } 

     iterator& operator++() { 
      ++i_; 
      return *this; 
     } 

     bool operator==(const iterator& r) const { 
      return i_ == r.i_; 
     } 
     bool operator!=(const iterator& r) const { 
      return i_ != r.i_; 
     } 

     nasty_thing* pnt_; 
     int i_; 
    }; 

    // needed by BOOST_FOREACH 
    using const_iterator = iterator; 

    wrapper(nasty_thing& n) 
    : begin_{ std::addressof(n), 0 } 
    , end_{std::addressof(n), n.length()} 
    {} 

    iterator begin() const { return begin_; } 
    iterator end() const { return end_; } 

    iterator begin_, end_; 
}; 

extern nasty_thing& nt; 

int main() 
{ 
    // simulate BOOST_FOREACH 
    BOOST_FOREACH(auto& i, wrapper(nt)) 
    { 

    } 
} 
+0

Это в данном примере. будет развиваться. –

+0

@juanchopanza обе версии предоставлены. –

+0

'std :: addressof' - C++ 11. Извините, я вижу, что есть 'boost :: addressof', так что это нормально, я могу его использовать. http://www.boost.org/doc/libs/1_61_0/libs/core/doc/html/core/addressof.html – Patryk

2

Там находятся Документы

http://www.boost.org/doc/libs/1_61_0/doc/html/foreach/extensibility.html

Это вас через распространение концепции диапазона к пользовательский контейнер без модификации контейнера.

Создайте range_begin и range_end бесплатные функции, которые берут ваш тип контейнера в пространстве имен th контейнера.

В пространстве имен boost, специализировать класс качества (ов), который говорит увеличить тип итератора:

template<> struct range_mutable_iterator<your::type::here> { 
    typedef your_iterator_type type; 
}; 
template<> struct range_const_iterator<your::type::here> { 
    typedef your_iterator_type type; 
}; 

И сделано.

Это, вероятно, может быть сделано с, специализирующимся boost::range_iterator<X>::type и boost::range_iterator<const X>::type и прямые перегрузки boost::begin/boost::end или ADL начала/конца перегрузками, но я думал, что я хотел бы использовать документированный путь расширяемости я нашел.

0

Я просто отправлю его для справки, так как Richard Hodges получил это почти право.

struct wrapper 
{ 
    struct iterator : std::iterator<std::forward_iterator_tag, ObservationReport> 
    { 
     iterator(ObservationReportList* p, int i) : pnt_(p), i_(i) {} 

     ObservationReport& operator*() { 
      return (*pnt_)[i_]; 
     } 

     iterator& operator++() { 
      ++i_; 
      return *this; 
     } 

     bool operator==(const iterator& r) const { 
      return i_ == r.i_; 
     } 
     bool operator!=(const iterator& r) const { 
      return i_ != r.i_; 
     } 

     ObservationReportList* pnt_; 
     int i_; 
    }; 

    typedef iterator const_iterator; // essential (in one way or another) 
    // http://www.boost.org/doc/libs/1_61_0/libs/range/doc/html/range/concepts/single_pass_range.html 

    wrapper(ObservationReportList & n) 
    : begin_(boost::addressof(n), 0) 
    , end_(boost::addressof(n), n.length()) 
    {} 

    iterator begin() { return begin_; } 
    iterator end() { return end_; } 
    iterator begin() const { return begin_; } // essential for Single Pass concept 
    iterator end() const { return end_; } // essential for Single Pass concept 

    iterator begin_, end_; 
}; 

// usage 

ObservationReportList reportList; 
// filling reportList 
BOOST_FOREACH(ObservationReport o, wrapper(reportList)) 
{ 
} 

Поэтому в основном мы пропустили const_iterator определение типа (здесь только ЬурейеЕ) и const версии begin() и end()

+0

ах, ты решил. круто. Извините, да, я не ясновидящий - я не знал интерфейс ObservationReport :) –

+0

@RichardHodges Вы согласны с этим ответом или хотите отредактировать свою собственную маркировку, что нам нужны 'const' перегрузки и' const_iterator' так что я могу принять его? – Patryk

+0

Обязательно принимайте его, если он помог вам в решении. Если вы позволите мне иметь интерфейсы, я могу это исправить. –