【问题标题】:iterator adapter to iterate just the values in a map?迭代器适配器仅迭代地图中的值?
【发布时间】:2010-09-20 12:42:12
【问题描述】:

在做了几年 C# 和最近的 Objective C 之后,我才刚刚回到 C++。

我之前做过的一件事是为 std::map 推出我自己的迭代器适配器,它将只引用值部分,而不是键值对。这是很常见和很自然的事情。 C# 为这个工具提供了它的 Dictionary 类的 Keys 和 Values 属性。 Objective-C 的 NSDictionary 同样具有 allKeys 和 allValues。

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

我正在考虑使用 Boost 的迭代器适配器来解决问题,但在我走这条路之前,我想我想在这里问一下是否有人知道 Boost 中的这种设施,或者其他现成的地方?

【问题讨论】:

标签: c++ maps iterator adapter


【解决方案1】:

替换之前的答案,以防其他人像我一样发现这个。从 boost 1.43 开始,提供了一些常用的范围适配器。在这种情况下,您需要 boost::adaptors::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

【讨论】:

  • 酷,感谢 Matt - 我在 boost 中没有看到过这种情况(自 2008 年以来我没有检查过!)
  • +1 有用,你可以这样做for ( auto value : mapVar | boost::adaptors::map_values)(C++11) 这太棒了
【解决方案2】:

我认为没有什么是开箱即用的。你可以使用 boost::make_transform。

template<typename T1, typename T2> T2& take_second(const std::pair<T1, T2> &a_pair) 
{
  return a_pair.second;
}

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

【讨论】:

  • 谢谢大卫。这与我之前所做的非常相似。根据我的喜好,它仍然需要很多样板。不过,投票支持您证明一个完全有效的答案。仍然希望更多...
  • 请注意,将boost::make_transform_iterator( Map::const_iterator , take_second&lt; Key, Value&gt; ) 包装在函数模板中很简单。这让沸腾
【解决方案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<int,int> input;
    for (int i = 0; i < 10; ++i)
    input.insert(std::make_pair(i, i * 10));

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

    return 0;
}

【讨论】:

    【解决方案4】:

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

    namespace detail
    {
    
    template<bool IsConst, bool IsVolatile, typename T>
    struct add_cv_if_c
    {
        typedef T type;
    };
    template<typename T>
    struct add_cv_if_c<true, false, T>
    {
        typedef const T type;
    };
    template<typename T>
    struct add_cv_if_c<false, true, T>
    {
        typedef volatile T type;
    };
    template<typename T>
    struct add_cv_if_c<true, true, T>
    {
        typedef const volatile T type;
    };
    
    template<typename TestConst, typename TestVolatile, typename T>
    struct add_cv_if: public add_cv_if_c<TestConst::value, TestVolatile::value, T>
    {};
    
    }   // 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<typename T, typename MemberType, MemberType T::*MemberPtr>
    struct access_member_f
    {
        // preserve cv-qualification of T for T::second_type
        typedef typename detail::add_cv_if<
            std::tr1::is_const<T>, 
            std::tr1::is_volatile<T>, 
            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<typename Iterator>
    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<Iterator>::reference
                >::type, 
                typename std::iterator_traits<Iterator>::value_type::second_type, 
                &std::iterator_traits<Iterator>::value_type::second
            >, 
            Iterator
        >
    {
        typedef boost::transform_iterator<
            access_member_f<
                typename std::tr1::remove_reference<
                    typename std::iterator_traits<Iterator>::reference
                >::type, 
                typename std::iterator_traits<Iterator>::value_type::second_type, 
                &std::iterator_traits<Iterator>::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<int, string> a_map_t;
      a_map_t a_map;
      a_map[0] = "zero";
      a_map[1] = "one";
      a_map[2] = "two";
    
      typedef accessing_second_iterator<a_map_t::const_iterator> ia_t;
      // note: specify the iterator adaptor type explicitly as template type, enabling 
      // implicit conversion from begin()/end()
      copy<ia_t>(a_map.begin(), a_map.end(),
        ostream_iterator<string>(cout, "\n")
      );
    }
    

    【讨论】:

      猜你喜欢
      • 2014-10-14
      • 1970-01-01
      • 2019-04-06
      • 2016-03-30
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 1970-01-01
      • 2023-03-15
      相关资源
      最近更新 更多