Ale*_*ter 6 c++ foreach boost iterator stl
基本上我正在做以下事情:
std::set<int> indices;
// ..fill indices
if (flag)
{
// we need to process in ascending order
BOOST_FOREACH (int i, indices)
{
process(i);
}
}
else
{
// we need to process in descending order
BOOST_REVERSE_FOREACH (int i, indices)
{
process(i);
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否有办法在C++ 03中编写相同的东西,只需要调用一个进程(i),以某种方式参数化处理顺序?像这样(显然在C++ 0x中不起作用,因为begin()和rbegin()返回不同的类型):
auto iter = flag ? indices.begin() : indices.rbegin();
auto end = flag ? indices.end() : indices.rend();
BOOST_FOREACH (int i, std::make_pair(iter, end))
{
process(i);
}
Run Code Online (Sandbox Code Playgroud)
你想要的东西可以用Boost.Variant实现.
我们的想法是定义一种新类型的迭代器,它存储一个变体(想象它类似于类固醇上的C联合),包含一个正向或反向迭代器:
template<class InputRange>
struct any_dir_iterator
: std::iterator_traits<typename boost::range_iterator<InputRange>::type> {
typedef typename boost::range_iterator<InputRange>::type forward_iterator;
typedef typename
boost::range_reverse_iterator<InputRange>::type reverse_iterator;
typedef boost::variant<forward_iterator, reverse_iterator> iterator_type;
iterator_type current_it, end_it;
any_dir_iterator(InputRange & input_range,
bool fwd = true,
bool end = false)
{
end_it = fwd ? iterator_type(boost::end(input_range))
: iterator_type(boost::rend(input_range));
if(end)
current_it = end_it;
else
current_it = fwd ? iterator_type(boost::begin(input_range))
: iterator_type(boost::rbegin(input_range));
}
reference operator*() const {
return boost::apply_visitor(dereference_visitor<any_dir_iterator>(),
current_it);
}
any_dir_iterator & operator++() {
boost::apply_visitor(increment_visitor<any_dir_iterator>(),
current_it);
return *this;
}
bool operator==(any_dir_iterator const & rhs) {
return boost::apply_visitor(equals_visitor<any_dir_iterator>(),
current_it, rhs.current_it);
}
};
Run Code Online (Sandbox Code Playgroud)
这类似于Adobe的任何迭代器,但不那么通用,这意味着与普通迭代器相比,它几乎没有性能开销.
正如您在上面的代码中看到的,所有逻辑都委托给静态访问者,我们定义如下:
template<class AnyDirIterator>
struct dereference_visitor
: boost::static_visitor<typename AnyDirIterator::iterator_type> {
typedef typename AnyDirIterator::reference result_type;
template<class FwdOrRevIterator>
result_type operator()(FwdOrRevIterator const & it) const {
return *it;
}
};
template<class AnyDirIterator>
struct increment_visitor
: boost::static_visitor<typename AnyDirIterator::iterator_type> {
typedef void result_type;
template<class FwdOrRevIterator>
result_type operator()(FwdOrRevIterator & it) const {
++it;
}
};
template<class AnyDirIterator>
struct equals_visitor
: boost::static_visitor<typename AnyDirIterator::iterator_type>
{
typedef bool result_type;
template <typename FwdOrRevIterator>
bool operator()(FwdOrRevIterator const & lhs,
FwdOrRevIterator const & rhs) const {
return lhs == rhs;
}
template <typename T, typename U>
bool operator()( const T &, const U & ) const {
return false; // comparing fwd to rev or vice-versa
}
};
Run Code Online (Sandbox Code Playgroud)
那是棘手的部分.但是我们仍然需要使用它更方便,为此我们定义了一个依赖于Boost.Range库提供的功能的辅助函数:
template<class InputRange>
boost::iterator_range<any_dir_iterator<InputRange> >
make_any_dir_range(InputRange & range, bool forward=true) {
typedef any_dir_iterator<InputRange> iterator;
return boost::make_iterator_range(iterator(range, forward),
iterator(range, forward, true));
}
Run Code Online (Sandbox Code Playgroud)
这就是全部.现在你可以写:
int main() {
int items[] = { 1, 2 };
typedef std::vector<int> container_type;
container_type container(items, items + sizeof(items)/sizeof(items[0]));
BOOST_FOREACH(int i, make_any_dir_range(container, true))
std::cout << i << " ";
std::cout << "\n";
BOOST_FOREACH(int i, make_any_dir_range(container, false))
std::cout << i << " ";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
哪个印刷品:
1 2
2 1
Run Code Online (Sandbox Code Playgroud)
这也适用于const容器,虽然我没有在main函数中显示出这种可能性.
使用Boost.Range产生的另一个好处是它适用于开箱即用的数组.所以你可以这样做:
int items[] = { 1, 2 };
BOOST_FOREACH(int i, make_any_dir_range(items, true)) // Prints "1 2"
std::cout << i << " ";
Run Code Online (Sandbox Code Playgroud)
为了保持这个答案的简短,我还有一些未实现的东西(但它们都是样板,不需要新访客):
这是Codepad中的所有代码.由于"将警告视为错误"政策,Codepad不会吞下它,但VS2008和GCC 4.4都在我的本地机器上编译好了.
UPDATE
我做了一些测试,显然boost::variant确实引入了一些运行时开销:与使用普通迭代器的等效版本相比,函数中的BOOST_FOREACH基于a 的循环main运行速度慢了4倍(在发布模式下编译时).检查这是最好的还是最差的,比Adobe的开销更有意思any_iterator.
| 归档时间: |
|
| 查看次数: |
369 次 |
| 最近记录: |