在不同类型的集合中进行迭代的通用代码
Common code to iterate through different types of collections
是否有一个优雅的解决方案可以使用公共代码迭代hash_map
/unordered_map
和list
/vector
集合?
一个例子:
template<typename collection>
class multicast
{
public:
typedef collection collection_type;
private:
collection_type& m_channels;
public:
multicast(collection_type& channels) : m_channels(channels) { }
void operator ()(const buffer::ptr& head, const buffer::ptr& cnt)
{
for each(collection_type::value_type& ch in m_channels)
ch->send(head, cnt); /* this is where the magic should happen? */
}
}
当collection_type
是unordered_map
时,此代码显然无法编译,因为collection_type::value_type
是pair
,因此访问实际值的代码应该不同:ch.second->send(head, cnt)
而不是ch->send(head, cnt)
。那么,当不需要关键部件时,最优雅的方法是什么呢?
是:
for (auto & x : collection) { do_stuff_with(x); }
或者:
for (auto it = std::begin(collection), end = std::end(collection); it != end; ++it)
{
do_stuff_with(*it);
}
如果基于范围的for
和auto
都不可用,则可以编写一个模板,该模板采用容器C
并使用C::value_type
和C::iterator
;或者您可以制作一个模板,它接受一对类型为Iter
的迭代器,并使用std::iterator_traits<Iter>::value_type
作为元素值类型。
第三,您可以使用for_each
和lambda:
std::for_each(colllection.begin(), collection.end(),
[](collection::value_type & x) { do_stuff_with(x); });
为了同时容纳单个元素和成对元素容器,您可以构建一个小包装器:
template <typename T> struct get_value_impl
{
typedef T value_type;
static value_type & get(T & t) { return t; }
};
template <typename K, typename V> struct get_value_impl<std::pair<K, V>>
{
typedef V value_type;
static value_type & get(std::pair<K,V> & p) { return p.second; }
};
template <typename T>
typename get_value_impl<T>::value_type & get_value(T & t)
{
return get_value_impl<T>::get(t);
}
现在您只能使用get_value(x)
或get_value(*it)
来获取值。
问题是list/vvector只包含一个值,而map-s包含一对键值。它们不是一回事,要以相同的方式迭代,你至少需要定义你感兴趣的部分
一旦定义好,您基本上需要一个接受迭代器的"取消围栏"操作,如果它的value_type是一对,则返回第二个元素,或者只是取消引用它。
// default case, returning itself
template<class T>
T& get_val(T& t) { return t; }
// case for pair (derefence for a map iterator)
template<class K, class V>
V& get_val(std::pair<const K, V>& s) { return s.second; }
// iterator dereference
template<class Iter>
decltype(get_val(*Iter()) deref_iter(const Iter& i)
{ return get_val(*i); }
当然,如果需要,还需要const_iter
版本。
现在:
for(auto i=container.begin(); i!=container-end(); ++i)
do_something_with(deref_iter(i));
无论是什么容器都是一样的。
相关文章:
- 为什么此代码的矢量迭代器没有停止?
- 我的代码在作为参数传入 .begin() 时不起作用,但在我将 .begin() 转换为迭代器后工作
- 如果我在下面的代码中使用 list 而不是 vector,为什么在我尝试在迭代器之间执行减法的行中编译失败?
- 在每次循环迭代时停止代码执行毫秒
- 在下面的 C++ 代码中,*(迭代器)和 *(++迭代器)是什么意思?
- 为什么在此代码中隐式转换为常量迭代器失败?
- 我通过迭代加法将二进制数转换为十进制并检查单个字符(请参阅代码)的方法有什么问题?
- 在此C++代码中,迭代器引用列表的哪个元素?
- 让宏将迭代参数传递到通过宏变量提供的代码体中
- 迭代列表以查找元素的出现.代码问题
- 重复输出的类型是怎么回事,它如何区分迭代次数和 Ascii 代码?
- 循环在此代码中仅迭代一次,而在另一个代码中正确迭代
- 如何使用迭代器显示以下代码的输出
- 如何调整我的代码以确保我的迭代代码接受用户输入
- 不使用循环如何迭代代码指令
- 在 OpenGL 中绘制立方体。迭代代码较短,但不起作用
- 段树的迭代代码
- ICU迭代代码点
- C++向量迭代代码无法编译,当向量作为对常量的引用传递时
- 使用模拟测试迭代代码——它有意义吗?