如何使自定义容器类型适应 BOOST_FOREACH?
How to adapt a custom container type to BOOST_FOREACH?
我想在我的代码库中将 BOOST_FOREACH
与我无法更改的旧容器类型之一一起使用。
我在该类型上定义了以下方法:
.length()
返回容器中的当前元素数
.operator[](unsigned i)
返回对索引 i
下的元素的引用
我知道我需要使我的容器类型满足 Single Pass Range Concept 正如 boost 文档所建议的那样,但我不知何故迷路了,因为我无法修改类型。
任何 hints/solutions 都会有用。
编辑
我试着按照建议去做,但是这段代码
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> >’
包装器可以提供所需的接口。
请注意,在此示例中,operator[] of nasty_thing returns 是对连续整数数组中一个整数的引用。
如果不是这种情况,我们需要根据索引使包装器工作。
#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))
{
}
}
有文档:
http://www.boost.org/doc/libs/1_61_0/doc/html/foreach/extensibility.html
引导您在不修改容器的情况下将范围概念扩展到自定义容器。
创建一个 range_begin
和 range_end
免费函数,将您的容器类型放入容器的命名空间。
在命名空间 boost
中,特化告诉 boost 迭代器类型的特征 class(es):
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 begin/end 重载的直接重载来完成,但我认为我会使用我找到的记录的可扩展性路径。
我只是 post 以供参考,因为 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()
我想在我的代码库中将 BOOST_FOREACH
与我无法更改的旧容器类型之一一起使用。
我在该类型上定义了以下方法:
.length()
返回容器中的当前元素数.operator[](unsigned i)
返回对索引i
下的元素的引用
我知道我需要使我的容器类型满足 Single Pass Range Concept 正如 boost 文档所建议的那样,但我不知何故迷路了,因为我无法修改类型。
任何 hints/solutions 都会有用。
编辑
我试着按照建议去做,但是这段代码
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> >’
包装器可以提供所需的接口。
请注意,在此示例中,operator[] of nasty_thing returns 是对连续整数数组中一个整数的引用。
如果不是这种情况,我们需要根据索引使包装器工作。
#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))
{
}
}
有文档:
http://www.boost.org/doc/libs/1_61_0/doc/html/foreach/extensibility.html
引导您在不修改容器的情况下将范围概念扩展到自定义容器。
创建一个 range_begin
和 range_end
免费函数,将您的容器类型放入容器的命名空间。
在命名空间 boost
中,特化告诉 boost 迭代器类型的特征 class(es):
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 begin/end 重载的直接重载来完成,但我认为我会使用我找到的记录的可扩展性路径。
我只是 post 以供参考,因为 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()