【问题标题】:How to use BOOST_FOREACH with a boost::ptr_map?如何使用带有 boost::ptr_map 的 BOOST_FOREACH?
【发布时间】:2009-01-20 14:26:55
【问题描述】:

如何通过 boost::ptr_map 有效地使用 BOOST_FOREACH(字符数/可读性)?

Kristo 在他的 answer 中演示了可以将 BOOST_FOREACH 与 ptr_map 一起使用,但与使用迭代器迭代 ptr_map 相比,它并没有真正为我节省任何打字(或使我的代码更易读):

typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
BOOST_FOREACH(IntPair p, mymap) {
    int i = p.first;
}

// vs.

boost::ptr_map<int, T>::iterator it;
for (it = mymap.begin(); it != mymap.end(); ++it) {
    // doSomething()
}

以下代码符合我的期望。它遵循如何将 BOOST_FOREACH 与 std::map 一起使用的标准方法。不幸的是,这不能编译:

boost::ptr_map<int, T> mymap;
// insert something into mymap
// ...

typedef pair<int, T> IntTpair;
BOOST_FOREACH (IntTpair &p, mymap) {
    int i = p.first;
}

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

    作为 STL 风格的容器,指针容器有一个 value_type 可以使用的 typedef:

    #include <boost/ptr_container/ptr_map.hpp>
    #include <boost/foreach.hpp>
    
    int main()
    {
        typedef boost::ptr_map<int, int> int_map;
        int_map mymap;
    
        BOOST_FOREACH(int_map::value_type p, mymap)
        {
        }
    }
    

    我发现对容器使用 typedef 使代码更容易编写。

    另外,你应该尽量避免在 boost 中使用 detail 命名空间的内容,这是一个包含实现细节的 boost 约定。

    【讨论】:

      【解决方案2】:

      我今天也遇到了同样的问题。不幸的是,丹尼尔的建议不适用于不断引用地图。在我的例子中,ptr_map 是一个类的成员,我想在一个 const 成员函数中循环它。借用丹尼尔的例子,这就是我必须做的事情:

      #include "boost/ptr_container/ptr_map.hpp"
      #include "boost/foreach.hpp"
      
      int main()
      {
          typedef boost::ptr_map<int, int> int_map;
          int_map mymap;
          const int_map& mymap_const_ref(mymap);
      
          BOOST_FOREACH(int_map::const_iterator::value_type p, mymap_const_ref)
          {
          }
      }
      

      好像int_map::const_iterator::value_type 等价于boost::ptr_container_detail::ref_pair&lt;int, const int* const&gt;

      【讨论】:

        【解决方案3】:

        使用元组节省打字并提高可读性:

        boost::ptr_map<int, T> mymap;
        int key;
        T * value;
        BOOST_FOREACH(boost::tie(key, value), mymap)
        {
            ...
        }
        

        【讨论】:

        • 这个编译过吗?查看tupleptr_container 的历史代码,我不禁断定它不能(并且任何尝试都失败了)。见this related question
        【解决方案4】:

        这个示例代码是用 g++ 4.1.2 为我编译的:

        #include "boost/ptr_container/ptr_map.hpp"
        #include "boost/foreach.hpp"
        
        int main()
        {
            boost::ptr_map<int, int> mymap;
        
            typedef boost::ptr_container_detail::ref_pair<int, int* const> IntPair;
            BOOST_FOREACH(IntPair p, mymap)
            {
                int i = p.first;
            }
        
            return 0;
        }
        

        【讨论】:

        • 谢谢克里斯托,这也是我最终想出的。然而,因为这个必须在 typedef 中写这么多,它并不是标准 for(ptr_map::iterator it = mymap.begin(); it != mymap.end( ); ++it) {} 了...
        • 我同意。我有兴趣看看是否有更短(更好?)的方式来编写 typedef。您还必须考虑您的同事。有多少人会说:“你写了一个疯狂的 typedef 只是为了让你使用 BOOST_FOREACH?只要写一个普通的 for 循环就可以了。” :)
        【解决方案5】:

        我使用这个自制模板,它添加了一个可以由 BOOST_FOREACH

        处理的迭代类型
        namspace homebrew
        {
          template
          <
            class Key,
            class T,
            class Compare        = std::less<Key>,
            class CloneAllocator = boost::heap_clone_allocator,
            class Allocator      = std::allocator< std::pair<const Key,void*> >
          >
          class ptr_map :
            public boost::ptr_map<Key,T,Compare,CloneAllocator,Allocator>
          {
          public:
            typedef boost::ptr_container_detail::ref_pair<Key,const T* const> const_ref;
            typedef boost::ptr_container_detail::ref_pair<Key,T* const> ref;
          };
        } 
        

        假设 foobar 是您最喜欢的两种类型;)

        typedef homebrew::ptr_map<foo,bar> Map;
        int f( const Map& m )
        {
          BOOST_FOREACH(Map::const_ref v, m)
          {
            v.first;  // foo
            v.second; // const bar* const
          }
        }
        

        int f( Map& m )
        {
          BOOST_FOREACH(Map::ref v, m)
          {
            v.first;  // foo
            v.second; // bar* const
          }
        }
        

        您必须使用哪一个似乎并不取决于您在循环中使用它的方式(常量或非常量),而是取决于地图的常量!所以下面会报错...

        int f( Map& m )
        {
          BOOST_FOREACH(Map::const_ref v, m)  // can't use const_ref because m isn't const
          {
            ...
          }
        }
        

        奇怪!不是吗?

        对我来说最棒的是这里建议的所有这些解决方案,这是第一个由 Eclipse CDT 语法着色正确处理的解决方案(使用“代码/问题”语法着色属性时)。

        【讨论】:

          【解决方案6】:

          它应该在没有引用的情况下编译:

          BOOST_FOREACH (IntTpair p, mymap)
          

          我认为问题在于映射实际上并没有将对象存储为对,而是作为一个以第一个元素为键的树结构,因此 BOOST_FOREACH 无法获得对一对的引用,但它可以创建一个临时副本一个。

          【讨论】:

            【解决方案7】:

            使用 ::value_type 不会让您对容器进行常量迭代。我使用迭代器引用类型

            typedef boost::ptr_map< myKey, myPtrType > MyMap;
            MyMap m;
            BOOST_FOREACH( MyMap::iterator::reference it, m )
              do_something( it.second );
            BOOST_FOREACH( MyMap::const_iterator::reference it, m )
              do_something_const( it.second );
            

            【讨论】:

              【解决方案8】:

              最后,我在循环之前声明了迭代变量。

              std::pair<std::string, TrailStep*> step;
              BOOST_FOREACH(step, m_steps)
              {
                  SAFE_DELETE(step.second);
              }
              

              但确实,应该有更简单的方法。 (用 D 代替?)

              【讨论】:

                【解决方案9】:

                您可以尝试这种超酷的方式来遍历地图、ptr 或其他方式: https://svn.boost.org/trac/boost/attachment/ticket/3469/foreach_field.hpp

                // no typedef needed
                BOOST_FOREACH_FIELD((int i)(const T& t), mymap)
                   // do something with i or t instead of first/second
                

                我不确定它是否适用于模板参数,但也许您只是将它用于抽象。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-08-14
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多