代码之家  ›  专栏  ›  技术社区  ›  Andreas Bonini

是否可以将boost::foreach与std::map一起使用?

  •  51
  • Andreas Bonini  · 技术社区  · 15 年前

    我发现 boost::foreach 非常有用,因为它节省了我很多写作。例如,假设我要打印列表中的所有元素:

    std::list<int> numbers = { 1, 2, 3, 4 };
    for (std::list<int>::iterator i = numbers.begin(); i != numbers.end(); ++i)
       cout << *i << " ";
    

    foreach使上面的代码更加简单:

    std::list<int> numbers = { 1, 2, 3, 4 };
    BOOST_FOREACH (int i, numbers)
       cout << i << " ";
    

    好多了!然而,我从来没有找到一种方法(如果可能的话)来使用它 std::map S.本文件仅包含以下类型的示例: vector string .

    8 回复  |  直到 12 年前
        1
  •  88
  •   Andreas Bonini    15 年前

    您需要使用:

    typedef std::map<int, int> map_type;
    map_type map = /* ... */;
    
    BOOST_FOREACH(const map_type::value_type& myPair, map)
    {
        // ...
    }
    

    原因是宏需要两个参数。当您试图内联对定义时,您引入了第二个逗号,使宏变为三个参数。预处理器不尊重任何C++结构,它只知道文本。

    所以当你说 BOOST_FOREACH(pair<int, int>, map) ,预处理器将看到宏的以下三个参数:

    1。 pair<int
    2。 int>
    三。 map

    这是错误的。这是 mentioned 在for each文档中。

        2
  •  20
  •   Manuel    15 年前

    我用 Boost's Range Ex library 它实现了一些奇特的范围适配器,用于遍历映射键或值。例如:

    map<int, string> foo;
    foo[3] = "three";
    foo[7] = "seven";
    
    BOOST_FOREACH(i, foo | map_keys)
       cout << i << "\n";
    
    
    BOOST_FOREACH(str, foo | map_values)
       cout << str << "\n";
    
        3
  •  3
  •   Fred Larson    15 年前

    当然可以。然而,技巧是,映射迭代器指向一对键和值。它看起来像这样:

    typedef std::map<std::string, int> MapType;
    MapType myMap;
    
    // ... fill the map...
    
    BOOST_FOREACH(MapType::value_type val, myMap)
    {
        std::cout << val.first << ": " << val.second << std::endl;
    }
    
        4
  •  2
  •   Jerry Coffin    15 年前

    这是有可能的,但这并不是最好的方法(正如我之前提到过的,因为每个人几乎从来没有这样做过,提升前臂只是稍微好一点)。对于你的第一个例子,我认为你最好:

    std::copy(numbers.begin(), numbers.end(), 
              std::ostream_iterator<int>(std::cout, " "));
    

    它与地图的工作原理非常相似,只是您必须为它定义运算符<<,因为还没有定义运算符:

    typedef map<std::string, int>::value_type vt;
    
    std::ostream &operator<<(std::ostream &os, vt &v) { 
        return os << v.first << ": " << v.second;
    }
    

    …再一次, std::copy 工作做得很好:

    std::copy(mymap.begin(), mymap.end(), 
              std::ostream_iterator<vt>(std::cout, "\n"));
    
        5
  •  2
  •   Paul Fultz II    13 年前

    映射对的typedefing令人困惑。迭代映射的最简单方法是使用元组(就像在Python中一样):

    std::map<int, int> mymap;
    int key, value;
    BOOST_FOREACH(boost::tie(key, value), mymap)
    {
        ...
    }
    

    别担心,这些逗号不会混淆预处理器,因为我在它们周围加了括号。

        6
  •  2
  •   marko.ristin    12 年前

    我不喜欢每次想在地图上使用foreach时都强制添加typedef的想法。下面是基于BoostForEach代码的实现:

    #ifndef MUNZEKONZA_FOREACH_IN_MAP 
    
    #include <boost/preprocessor/cat.hpp>
    #define MUNZEKONZA_FOREACH_IN_MAP_ID(x)  BOOST_PP_CAT(x, __LINE__)
    
    namespace munzekonza {
    namespace foreach_in_map_private {
    inline bool set_false(bool& b) {
      b = false;
      return false;
    }
    
    }
    }
    
    #define MUNZEKONZA_FOREACH_IN_MAP(key, value, map)                            \
    for(auto MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) = map.begin();      \
            MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();)       \
    for(bool MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true;       \
          MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) &&               \
          MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();          \
          (MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue)) ?              \
            ((void)++MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)) :          \
            (void)0)                                                              \
      if( munzekonza::foreach_in_map_private::set_false(                          \
              MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue))) {} else    \
      for( key = MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)->first;         \
            !MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue);              \
            MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true)        \
      if( munzekonza::foreach_in_map_private::set_false(                          \
              MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue))) {} else    \
      for( value = MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)->second;      \
            !MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue);              \
            MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true)        
    

    然后您可以在代码中使用它: #在地图munzekonza中定义foreach,在地图中定义foreach

    std::map<int, std::string> mymap;
    mymap[0] = "oi";
    mymap[1] = "noi";
    
    std::map<int, std::string> newmap;
    
    foreach_in_map(int key, const std::string& value, mymap) {
      newmap[key] = value;
    }
    
    ASSERT_EQ( newmap.size(), 2 );
    ASSERT_EQ( newmap.count(0), 1 );
    ASSERT_EQ( newmap.count(1), 1 );
    ASSERT_EQ( newmap.at(0), "oi" );
    ASSERT_EQ( newmap.at(1), "noi" );
    

    还可以更改值: #在地图munzekonza中定义foreach,在地图中定义foreach

    std::map<int, std::string> mymap;
    
    mymap[0] = "oi";
    mymap[1] = "noi";
    
    std::map<int, std::string> newmap;
    
    foreach_in_map(int key, std::string& value, mymap) {
      value = "voronoi" + boost::lexical_cast<std::string>(key);
    }
    
    ASSERT_EQ( mymap.size(), 2 );
    ASSERT_EQ( mymap.count(0), 1 );
    ASSERT_EQ( mymap.count(1), 1 );
    ASSERT_EQ( mymap.at(0), "voronoi0" );
    ASSERT_EQ( mymap.at(1), "voronoi1" );
    
        7
  •  1
  •   Loki Astari    15 年前

    对:

    typedef std::map<std::string,int>    MyMap;
    
    MyMap    myMap;
    
    BOOST_FOREACH(MyMap::value_type loop, myMap)
    { 
           // Stuff
    }
    
        8
  •  0
  •   Andreas Bonini    14 年前

    在C++ 0x中,你可以更容易地做:

    map<int, string> entries;
    /* Fill entries */
    
    foreach(auto i, entries)
       cout << boost::format("%d = %s\n") % i.first % i.second;