在不同类型的集合中进行迭代的通用代码

Common code to iterate through different types of collections

本文关键字:迭代 代码 同类型 集合      更新时间:2023-10-16

是否有一个优雅的解决方案可以使用公共代码迭代hash_map/unordered_maplist/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_typeunordered_map时,此代码显然无法编译,因为collection_type::value_typepair,因此访问实际值的代码应该不同: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);
}

如果基于范围的forauto都不可用,则可以编写一个模板,该模板采用容器C并使用C::value_typeC::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));

无论是什么容器都是一样的。