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;
}