考虑以下代码,使用BOOST_FOREACH宏迭代一个侵入式列表:
#include <boost/foreach.hpp>
#include <boost/intrusive/list.hpp>
typedef boost::intrusive::list<
boost::intrusive::list_base_hook<> > MyList;
void iterate (const MyList& xs) {
BOOST_FOREACH (MyList::const_reference node, xs);
}
int main () {
MyList xs;
iterate (xs);
return 0;
}
鉴于升级版本1.48,代码在clang 3.2(SVN)和gcc 4.6.3中失败,但与gcc 4.5.3一起使用。使用非const限定参数xs
到iterate
代码可以正常工作。启用C ++ 11后,所有编译器都会接受代码。当使用boost-1.46时,两个gcc版本都接受代码,但clang仍然没有。
手头的代码是否误用了BOOST_FOREACH
宏,或者是提升方面的错误?有没有比使用常规for循环迭代更好的解决方法?
答案 0 :(得分:2)
以下是我可以从日志中收集的内容以及我对失败原因的推断。
简短版本:由于某种原因BOOST_FOREACH
尝试复制不可能的数据。
Extensibility页面上有一条注释:
使
BOOST_FOREACH
使用不可复制的序列类型对于不可复制的序列类型,我们需要告诉
BOOST_FOREACH
不要尝试复制。如果我们的类型继承自boost::noncopyable
,则无需进一步操作。如果没有,我们必须专门化boost::foreach::is_noncopyable<>
模板[...]另一种实现相同效果的方法是覆盖全局boost_foreach_is_noncopyable()
函数。这样做具有可移植到较旧编译器的优点。
从诊断结果来看,尚不清楚该类型是否配置正确,因此您可能想要试一试。
修剪诊断和分析。
/usr/include/boost/foreach.hpp:571:37: error: no matching constructor for initialization of 'boost::intrusive::list< >'
::new(this->data.address()) T(t);
^ ~
/usr/include/boost/foreach.hpp:648:51: note: in instantiation of member function 'boost::foreach_detail_::simple_variant<boost::intrusive::list< > >::simple_variant' requested here
return auto_any<simple_variant<T> >(*rvalue ? simple_variant<T>(t) : simple_variant<T>(&t));
^
/usr/include/boost/intrusive/list.hpp:1490:35: note: candidate constructor not viable: 1st argument ('const boost::intrusive::list< >') would lose const qualifier
BOOST_MOVABLE_BUT_NOT_COPYABLE(list)
^
/usr/include/boost/move/move.hpp:371:7: note: expanded from macro 'BOOST_MOVABLE_BUT_NOT_COPYABLE'
TYPE(TYPE &);\
/usr/include/boost/intrusive/list.hpp:1497:4: note: candidate constructor not viable: no known conversion from 'const boost::intrusive::list< >' to 'const value_traits' (aka 'const boost::intrusive::detail::base_hook_traits<boost::intrusive::list_base_hook< >, boost::intrusive::list_node_traits<void *>, 1, boost::intrusive::default_tag, 1>') for 1st argument;
list(const value_traits &v_traits = value_traits())
^
/usr/include/boost/intrusive/list.hpp:1506:4: note: candidate constructor not viable: no known conversion from 'const boost::intrusive::list< >' to '::boost::rv<list< >> &' for 1st argument;
list(BOOST_RV_REF(list) x)
^
/usr/include/boost/intrusive/list.hpp:1502:4: note: candidate constructor template not viable: requires at least 2 arguments, but 1 was provided
list(Iterator b, Iterator e, const value_traits &v_traits = value_traits())
^
我试图尽可能地隔离错误(删除回溯等等)。显然问题源于boost::intrusive::list
,更确切地说,无法从{{1}构建新的boost::intrusive::list<>
}}
最有前途的构造函数由宏定义:
boost::intrusive::list<> const
扩展为
BOOST_MOVABLE_BUT_NOT_COPYABLE(list)
这是boost模拟C ++ 03中不可复制类型的移动语义的方式。但是,由于list(list&);
限定符将丢失,因此无法从const
项移动。
这看起来是const
用来避免对容器参数进行多次评估的诡计的一部分(如果它是一个函数调用)虽然我有点惊讶它试图在这里复制参数。 / p>
答案 1 :(得分:1)
由于您使用的是gcc&gt; 4.6和clang 3.2,你可以使用C ++ 11的基于范围的looops:
#include <boost/foreach.hpp>
#include <boost/intrusive/list.hpp>
typedef boost::intrusive::list<
boost::intrusive::list_base_hook<> > MyList;
void iterate (const MyList& xs) {
for(const auto &node : xs) {
// do something with node
}
}
int main () {
MyList xs;
iterate (xs);
return 0;
}
您也可以使用std::for_each
:
void iterate (const MyList& xs) {
std::for_each(xs.begin(), xs.end(),
[](MyList::const_reference node) {
// do something with node
}
);
}