当前位置:  开发笔记 > 编程语言 > 正文

迭代器适配器只迭代映射中的值?

如何解决《迭代器适配器只迭代映射中的值?》经验,为你挑选了4个好方法。

经过几年的C#和最近的Objective C,我刚刚回到C++.

我之前做过的一件事就是为std :: map滚动我自己的迭代器适配器,它将仅仅反映值部分,而不是键值对.这是一个非常普遍和自然的事情.C#为此工具提供了其Dictionary类的Keys和Values属性.类似地,Objective-C的NSDictionary具有allKeys和allValues.

自从我"离开"以来,Boost已经收购了Range和ForEach库,我现在正在广泛使用它们.我想知道两者之间是否有一些设施可以做同样的事情,但我找不到任何东西.

我正在考虑使用Boost的迭代器适配器来解决问题,但在我沿着这条路走下去之前,我想我会问这里是否有人知道Boost中的这样一个设施,还是其他现成的设施?



1> Matt Chamber..:

取代之前的答案,以防其他人发现这个,就像我做的那样.从增强1.43开始,提供了一些常用的范围适配器.在这种情况下,您需要boost :: adapters :: map_values.相关示例:http: //www.boost.org/doc/libs/1_46_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html#range.reference.adaptors.reference.map_values. map_values_example


+1有用,你可以做这个`for(auto value:mapVar | boost :: adapters :: map_values)`(C++ 11)哪个很棒

2> David Nehme..:

我不认为有任何开箱即用的东西.你可以使用boost :: make_transform.

template T2& take_second(const std::pair &a_pair) 
{
  return a_pair.second;
}

void run_map_value()
{
  map a_map;
  a_map[0] = "zero";
  a_map[1] = "one";
  a_map[2] = "two";
  copy( boost::make_transform_iterator(a_map.begin(), take_second),
    boost::make_transform_iterator(a_map.end(), take_second),
    ostream_iterator(cout, "\n")
    );
}


Thanks David. That's pretty similar to what I have done before. It still requires a lot of boilerplate for my liking. Voting you up for proving a perfectly valid answer though. Still hoping for more...

3> 小智..:

有一个增压范围适配器正是为了这个目的.请参阅http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/range/reference/adaptors/reference/map_values.html

(这个例子来自那里)

int main(int argc, const char* argv[])
{
    using namespace boost::assign;
    using namespace boost::adaptors;

    std::map input;
    for (int i = 0; i < 10; ++i)
    input.insert(std::make_pair(i, i * 10));

    boost::copy(
        input | map_values,
        std::ostream_iterator(std::cout, ","));

    return 0;
}



4> klaus triend..:

继续大卫的回答,通过从boost :: transform_iterator创建一个派生类,还有另一种可能性.我在我的项目中使用此解决方案:

namespace detail
{

template
struct add_cv_if_c
{
    typedef T type;
};
template
struct add_cv_if_c
{
    typedef const T type;
};
template
struct add_cv_if_c
{
    typedef volatile T type;
};
template
struct add_cv_if_c
{
    typedef const volatile T type;
};

template
struct add_cv_if: public add_cv_if_c
{};

}   // namespace detail


/** An unary function that accesses the member of class T specified in the MemberPtr template parameter.

    The cv-qualification of T is preserved for MemberType
 */
template
struct access_member_f
{
    // preserve cv-qualification of T for T::second_type
    typedef typename detail::add_cv_if<
        std::tr1::is_const, 
        std::tr1::is_volatile, 
        MemberType
    >::type& result_type;

    result_type operator ()(T& t) const
    {
        return t.*MemberPtr;
    }
};

/** @short  An iterator adaptor accessing the member called 'second' of the class the 
    iterator is pointing to.
 */
template
class accessing_second_iterator: public 
    boost::transform_iterator<
        access_member_f<
            // note: we use the Iterator's reference because this type 
            // is the cv-qualified iterated type (as opposed to value_type).
            // We want to preserve the cv-qualification because the iterator 
            // might be a const_iterator e.g. iterating a const 
            // std::pair<> but std::pair<>::second_type isn't automatically 
            // const just because the pair is const - access_member_f is 
            // preserving the cv-qualification, otherwise compiler errors will 
            // be the result
            typename std::tr1::remove_reference<
                typename std::iterator_traits::reference
            >::type, 
            typename std::iterator_traits::value_type::second_type, 
            &std::iterator_traits::value_type::second
        >, 
        Iterator
    >
{
    typedef boost::transform_iterator<
        access_member_f<
            typename std::tr1::remove_reference<
                typename std::iterator_traits::reference
            >::type, 
            typename std::iterator_traits::value_type::second_type, 
            &std::iterator_traits::value_type::second
        >, 
        Iterator
    > baseclass;

public:
    accessing_second_iterator(): 
        baseclass()
    {}

    // note: allow implicit conversion from Iterator
    accessing_second_iterator(Iterator it): 
        baseclass(it)
    {}
};

这导致更清晰的代码:

void run_map_value()
{
  typedef map a_map_t;
  a_map_t a_map;
  a_map[0] = "zero";
  a_map[1] = "one";
  a_map[2] = "two";

  typedef accessing_second_iterator ia_t;
  // note: specify the iterator adaptor type explicitly as template type, enabling 
  // implicit conversion from begin()/end()
  copy(a_map.begin(), a_map.end(),
    ostream_iterator(cout, "\n")
  );
}

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有