boost.foreach库使用起来非常方便,但实现的技巧可算是精彩绝伦。写基础库就应该如此,困难的永远留给自己,将光鲜的一面奉献出来。
简单使用示例:
std::vector<int> vecs;
vecs.push_back(1);
vecs.push_back(2);
vecs.push_back(3);
vecs.push_back(4);
vecs.push_back(5);
BOOST_FOREACH(int index, vecs) {
_asm nop;
}
vecs.push_back(1);
vecs.push_back(2);
vecs.push_back(3);
vecs.push_back(4);
vecs.push_back(5);
BOOST_FOREACH(int index, vecs) {
_asm nop;
}
顺序遍历十分方便,但有时候想获取更多的信息(如:当前遍历的位置索引等),就不得不需要获取到当前的迭代器位置。
观察foreach的内部实现,_foreach_cur变量存放当前迭代器的信息,但也仅仅如此,无法直观地获取具体的迭代器类型。
要使用_foreach_cur变量,必须书写相应的辅助函数.
下面以获取foreach的两个迭代器之间的距离为例:
namespace boost {
namespace foreach_detail_ {
template<typename T, typename C>
inline
typename boost::iterator_difference<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>::type
distance(auto_any_t first, auto_any_t last, type2type<T, C> *)
{
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iter_t;
return std::distance(auto_any_cast<iter_t, boost::mpl::false_>(first),
auto_any_cast<iter_t, boost::mpl::false_>(last));
}
} // namespace foreach_detail_
} // namespace boost
namespace foreach_detail_ {
template<typename T, typename C>
inline
typename boost::iterator_difference<BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type>::type
distance(auto_any_t first, auto_any_t last, type2type<T, C> *)
{
typedef BOOST_DEDUCED_TYPENAME foreach_iterator<T, C>::type iter_t;
return std::distance(auto_any_cast<iter_t, boost::mpl::false_>(first),
auto_any_cast<iter_t, boost::mpl::false_>(last));
}
} // namespace foreach_detail_
} // namespace boost
获取当前的迭代位置到容器开始的距离:
#define BOOST_FOREACH_DISTANCE(COL) \
boost::foreach_detail_::distance(BOOST_FOREACH_BEGIN(COL), _foreach_cur, BOOST_FOREACH_TYPEOF(COL))
boost::foreach_detail_::distance(BOOST_FOREACH_BEGIN(COL), _foreach_cur, BOOST_FOREACH_TYPEOF(COL))
宏参数COL为容器变量或者返回值为容器的函数,根据foreach的实现技巧,该参数并不会被求值,仅仅用其做模板参数的推导。
使用示例:
BOOST_FOREACH(int index, vecs) {
assert(index == BOOST_FOREACH_DEREF(vecs));
size_t dis = BOOST_FOREACH_DISTANCE(vecs);
_asm nop;
}
assert(index == BOOST_FOREACH_DEREF(vecs));
size_t dis = BOOST_FOREACH_DISTANCE(vecs);
_asm nop;
}