【问题标题】:Why doesn’t std::map provide key_iterator and value_iterator?为什么 std::map 不提供 key_iterator 和 value_iterator?
【发布时间】:2013-11-30 13:23:05
【问题描述】:

我在 C++03 环境中工作,将函数应用到地图的每个键是很多代码:

const std::map<X,Y>::const_iterator end = m_map.end();
for (std::map<X,Y>::const_iterator element = m_map.begin(); element != end; ++element)
{
   func( element->first );
}

如果存在key_iterator,相同的代码可以利用std::for_each

std::for_each( m_map.key_begin(), m_map.key_end(), &func );

那为什么不提供呢?有没有办法让第一种模式适应第二种模式?

【问题讨论】:

  • 您可以像for(iterator it=c.begin(), end=c.end(); ...) 一样在循环头中同时初始化itend,以减少“大量代码”。也就是说,提供您建议的迭代器也会让我想知道它们是否提供了与普通迭代器不同的元素顺序或数量,这反过来又会使代码变得不那么清晰。
  • 对于“为什么 C++ 标准库没有 X”的答案几乎总是“他们没有及时添加它”。对于要添加到图书馆的东西,必须有人为它写一个提案,委员会必须讨论它并批准它,而这并没有发生。它不在那里,因为没有人把它放在那里。
  • 看看boost::transform_iterator。对std::pair&lt;key, value_type&gt; 的键或值进行切片大约需要 3 行代码。如果您有足够的耐心,我会在可以访问代码时粘贴代码。
  • boost::adaptors::map_keys 的代码行数更少。

标签: c++ iterator standard-library stdmap c++03


【解决方案1】:

是的,这是一个愚蠢的缺点。但它很容易纠正:您可以编写自己的通用 key_iterator 类,该类可以从映射(对)迭代器构造。我已经做到了,只有几行代码,然后做value_iterator也很简单。

【讨论】:

    【解决方案2】:

    std::map&lt;K, V&gt; 不需要为键和/或值提供迭代器:可以基于现有迭代器轻松构建这样的迭代器。好吧,这并不像应该/可能的那么容易,但它肯定是可行的。我知道Boost 有一个迭代器适配器库。

    真正的问题可能是:为什么标准 C++ 库不为项目迭代器提供迭代器适配器?在我看来,简短的回答是:因为一般来说,您不想修改迭代器来选择访问的属性!您宁愿想要投影,或者更一般地说,转换访问的值,但仍保持相同的位置概念。表述不同,我认为有必要将定位的概念(即推进迭代器并测试它们的位置是否有效)与访问给定位置的属性分开。我设想的方法是这样的:

    std::for_each(m_map.key_pm(), m_map.begin(), m_map.end(), &func);
    

    或者,如果您知道从映射的迭代器获得的底层结构是std::pair&lt;K const, V&gt;std::map&lt;K, V&gt; 的情况是这样,但对于与关联容器类似的其他容器不一定如此;例如,基于 b 的关联容器-tree 将受益于将键和值拆分为单独的实体):

    std::for_each(_1st, m_map.begin(), m_map.end(), &func);
    

    我的STL 2.0 page 是一篇 [不完整的] 文章,其中包含更多关于我认为应该如何改进标准 C++ 库算法的详细信息,包括上述将迭代器分为定位(游标)和属性访问(属性映射) )。

    【讨论】:

      【解决方案3】:

      那为什么不提供呢?

      我不知道。

      有没有办法让第一种模式适应第二种模式?

      除了制作“密钥迭代器”(参见我的评论和其他答案)之外,您还可以在 func 周围编写一个小包装器,例如:

      class FuncOnFirst { // (maybe find a better name)
      public:
          void operator()(std::map<X,Y>::value_type const& e) const { func(e.first); }
      };
      

      然后使用:

      std::for_each( m_map.begin(), m_map.end(), FuncOnFirst() );
      

      更通用的包装器:

      class FuncOnFirst { // (maybe find a better name)
      public:
          template<typename T, typename U>
          void operator()(std::pair<T, U> const& p) const { func(p.first); }
      };
      

      【讨论】:

        【解决方案4】:

        不需要key_iteratorvalue_iterator,因为std::mapvalue_typestd::pair&lt;const X, Y&gt;,这就是for_each() 调用的函数(或仿函数)将在其上运行的。由于pair 聚合在映射使用的二叉树的底层节点中,因此单个迭代器没有性能提升。

        通过std::pair 访问键和值并不费力。

        #include <iostream>
        #include <map>
        
        typedef std::map<unsigned, unsigned> Map;
        
        void F(const Map::value_type &v)
        {
            std::cout << "Key: " << v.first << " Value: " << v.second << std::endl;
        }
        
        int main(int argc, const char * argv[])
        {
            Map map;
        
            map.insert(std::make_pair(10, 20));
            map.insert(std::make_pair(43, 10));
            map.insert(std::make_pair(5, 55));
        
            std::for_each(map.begin(), map.end(), F);
        
            return 0;
        }
        

        它给出了输出:

        Key: 5 Value: 55
        Key: 10 Value: 20
        Key: 43 Value: 10
        Program ended with exit code: 0
        

        【讨论】:

          猜你喜欢
          • 2022-11-17
          • 2021-12-17
          • 2017-08-15
          • 2012-05-04
          • 1970-01-01
          • 1970-01-01
          • 2013-07-21
          • 1970-01-01
          • 2012-01-17
          相关资源
          最近更新 更多