gcc和cpp中的" foreach值"宏
我有一个C ++中经常使用的" foreach"宏,该宏适用于大多数STL容器:
#define foreach(var, container) \ for(typeof((container).begin()) var = (container).begin(); \ var != (container).end(); \ ++var)
(请注意,'typeof'是gcc扩展名。)它的用法如下:
std::vector< Blorgus > blorgi = ...; foreach(blorgus, blorgi) { blorgus->draw(); }
我想对地图的值进行类似的迭代。也许将其称为" foreach_value"。所以不要写
foreach(pair, mymap) { pair->second->foo(); }
我会写
foreach_value(v, mymap) { v.foo(); }
我无法提供一个可以做到这一点的宏,因为它需要声明两个变量:迭代器和值变量(上面的" v")。我不知道如何在for循环的初始化程序中执行此操作,即使使用gcc扩展也是如此。我可以在foreach_value调用之前声明它,但随后它将与同一范围内的foreach_value宏的其他实例冲突。如果我可以在迭代器变量名称后加上当前行号,则可以使用,但是我不知道该怎么做。
解决方案
回答
我们可以定义一个模板类,该类将mymap的类型作为模板参数,并通过重载*和->来像对值进行迭代的行为。
回答
我们会在寻找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 }
回答
我们是否考虑过使用Boost库?他们实现了一个foreach
宏,它可能比我们将要编写的任何东西都更强大...而且还有transform_iterator
似乎可以用来完成所需内容的第二次提取。
不幸的是,由于我对C ++不够了解,所以我无法确切告诉我们如何使用它:)谷歌搜索提供了一些有希望的答案:comp.lang.c ++。moderated,Boost transform_iterator用例。
回答
我们可以使用两个循环来执行此操作。第一个声明了迭代器,其名称是容器变量的函数(如果我们担心与自己的代码发生冲突,可以使此丑陋)。第二个声明值变量。
#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)
通过使用相同的循环终止条件,外部循环只会发生一次(如果幸运的话,它会被优化掉)。另外,如果映射为空,则避免在迭代器上调用-> second。对于内循环的增量,这也是三元运算符的原因。最后,我们将var保留为最后一个值,因为不会再次引用它。
我们可以内联ci(container),但是我认为它使宏更具可读性。
回答
STL转换功能也执行类似的操作。
参数为(按顺序):
- 指定容器开始的输入迭代器
- 指定容器末尾的输入迭代器
- 一个输出迭代器,用于定义将输出放置在何处(对于就地转换,类似于for-each,只需在#1中传递输入迭代器)
- 在每个元素上执行的一元函数(函数对象)
对于一个非常简单的示例,我们可以通过以下方式将字符串中的每个字符大写:
#include <iostream> #include <string> #include <algorithm> #include <cctype> int main(int argc, char* argv[]) { std::string s("my lowercase string"); std::transform(s.begin(), s.end(), s.begin(), toupper); std::cout << s << std::endl; // "MY LOWERCASE STRING" }
或者,还有一个累加函数,它允许在调用函数对象之间保留一些值。累加不会像变换一样修改输入容器中的数据。
回答
Boost :: For_each是迄今为止最好的选择。有趣的是,它们实际上给是宏BOOST_FOREACH(),我们可以将其包装并#define为我们真正想要在代码中调用的内容。大多数人都会选择老式的" foreach",但是其他商店可能具有不同的编码标准,因此符合这种思维方式。 Boost还为C ++开发人员提供了许多其他好处!很值得使用。
回答
#define foreach(var, container) for (typeof((container).begin()) var = (container).begin(); var != (container).end(); ++var)
C ++中没有typeof ...如何为我们编译? (当然不是便携式的)
回答
我创建了一个带有一些foreach()变体的Foreach.h辅助程序,包括对局部变量和指针进行操作的变体,还有一个额外的版本,可以防止从循环内删除元素。因此,使用我的宏的代码看起来不错,很舒适,如下所示:
#include <cstdio> #include <vector> #include "foreach.h" int main() { // make int vector and fill it vector<int> k; for (int i=0; i<10; ++i) k.push_back(i); // show what the upper loop filled foreach_ (it, k) printf("%i ",(*it)); printf("\n"); // show all of the data, but get rid of 4 // http://en.wikipedia.org/wiki/Tetraphobia :) foreachdel_ (it, k) { if (*it == 4) it=k.erase(it); printf("%i ",(*it)); } printf("\n"); return 0; }
输出:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 5 6 7 8 9
我的Foreach.h提供了以下宏:
- foreach()-指针的常规foreach
- foreach_()-局部变量的常规foreach
- foreachdel()-foreach版本,用于检查循环内是否删除,指针版本
- foreachdel_()-foreach版本,其中检查循环内是否删除,局部变量版本
他们一定会为我工作,我希望他们也会使生活更轻松:)