gcc&cpp中的"foreach values"宏

sfi*_*ink 12 c++ gcc

我有一个'foreach'宏我经常在C++中使用,适用于大多数STL容器:

#define foreach(var, container) \
  for(typeof((container).begin()) var = (container).begin(); \
      var != (container).end(); \
      ++var)
Run Code Online (Sandbox Code Playgroud)

(注意'typeof'是gcc扩展名.)它的使用方式如下:

std::vector< Blorgus > blorgi = ...;
foreach(blorgus, blorgi) {
  blorgus->draw();
}
Run Code Online (Sandbox Code Playgroud)

我想做一些类似迭代地图值的东西.也许称之为"foreach_value".所以不要写作

foreach(pair, mymap) {
  pair->second->foo();
}
Run Code Online (Sandbox Code Playgroud)

我会写的

foreach_value(v, mymap) {
  v.foo();
}
Run Code Online (Sandbox Code Playgroud)

我不能想出一个会这样做的宏,因为它需要声明两个变量:迭代器和值变量(上面的'v').我不知道如何在for循环的初始化器中做到这一点,即使使用gcc扩展.我可以在foreach_value调用之前声明它,但是它会与同一范围内的foreach_value宏的其他实例冲突.如果我可以将当​​前行号后缀为迭代器变量名,它可以工作,但我不知道该怎么做.

Tom*_*eys 8

您将寻找BOOST_FOREACH - 他们已经为您完成了所有工作!

如果你想要自己动手,可以在C++的任何地方声明一个块,这可以解决你的中间存储器itr-> second的范围问题......

// Valid C++ code (which does nothing useful)
{
  int a = 21; // Which could be storage of your value type
}
// a out of scope here
{ 
  int a = 32; // Does not conflict with a above
}
Run Code Online (Sandbox Code Playgroud)


arc*_*hop 5

您可以使用两个循环来完成此操作。第一个声明迭代器,其名称是容器变量的函数(如果您担心与您自己的代码发生冲突,您可以使它更难看)。第二个声明值变量。

#define ci(container) container ## iter
#define foreach_value(var, container) \
    for (typeof((container).begin()) ci(container) = container.begin(); \
         ci(container) != container.end(); ) \
        for (typeof(ci(container)->second)* var = &ci(container)->second; \
             ci(container) != container.end(); \
             (++ci(container) != container.end()) ? \
                 (var = &ci(container)->second) : var)
Run Code Online (Sandbox Code Playgroud)

通过使用相同的循环终止条件,外循环只发生一次(如果幸运的话,会被优化掉)。此外,如果地图为空,则避免在迭代器上调用 ->second 。这与内循环增量中三元运算符的原因相同;最后,我们只将 var 留在最后一个值,因为它不会再次被引用。

您可以内联 ci(container),但我认为它使宏更具可读性。