1

我想BOOST_FOREACH在我的代码库中使用一种无​​法更改的旧容器类型。

我在该类型上定义了以下方法:

  • .length()返回容器中当前元素的数量
  • .operator[](unsigned i)返回对索引下元素的引用i

我知道我需要让我的容器类型满足单程范围概念,正如 boost 文档所建议的那样,但由于我无法修改类型,我不知何故迷失了方向。

任何提示/解决方案都会很有用。

编辑

我试图提出建议,但这段代码

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> >’
4

3 回答 3

3

包装器可以提供所需的接口。

请注意,在此示例中, nasty_thing 的 operator[] 返回对连续 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))
    {

    }
}
于 2016-09-12T11:57:23.400 回答
2

有文档:

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

这将引导您将范围概念扩展到自定义容器,而无需修改容器。

在容器的命名空间中创建一个range_begin和免费的函数,将您的容器类型。range_end

在 namespaceboost中,专门化告诉 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>::typeboost::range_iterator<const X>::type直接重载boost::begin/boost::end或 ADL 开始/结束重载来完成,但我想我会使用我找到的文档化可扩展性路径。

于 2016-09-12T12:34:55.633 回答
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类型定义(这里只有一个 typedef)和const版本begin()end()

于 2016-09-12T13:35:39.523 回答