我有一个'foreach'宏我经常在C ++中使用,适用于大多数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宏的其他实例冲突。 如果我可以将当​​前行号后缀为迭代器变量名,它可以工作,但我不知道该怎么做。

===============>>#1 票数: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
}

===============>>#2 票数:4 已采纳

您可以使用两个循环执行此操作。 第一个声明了迭代器,其名称是容器变量的函数(如果您担心与自己的代码冲突,可以使这个更丑陋)。 第二个声明了值变量。

#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(容器),但我认为它使宏更具可读性。

===============>>#3 票数:3

STL 转换函数也做了类似的事情。

参数是(按顺序):

  1. 指定容器开头的输入迭代器
  2. 指定容器末尾的输入迭代器
  3. 一个输出迭代器,用于定义输出的位置(对于就地变换,类似于for-each,只需传递#1中的输入迭代器)
  4. 要对每个元素执行的一元函数(函数对象)

对于一个非常简单的示例,您可以通过以下方式将字符串中的每个字符大写:

#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"
}

或者,还有accumulate函数,它允许在调用函数对象之间保留一些值。 累加不修改在输入容器内的数据作为与变换的情况。

===============>>#4 票数:1

我创建了一个Foreach.h辅助函数,其中包含一些foreach()变体,包括在局部变量和指针上运行的变量,还有一个额外的版本可以防止从循环中删除元素。 所以使用我的宏的代码看起来很漂亮和舒适,如下所示:

#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版本,在循环内检查删除,局部变量版本

他们肯定会为我工作,我希望他们也会让你的生活更轻松:)

===============>>#5 票数:1

这个问题分为两部分。 你需要以某种方式(1)在map的 (而不是键)上生成迭代器(或者更确切地说,是一个可迭代的序列),并且(2)使用宏来进行迭代而不需要很多样板。

最干净的解决方案是使用Boost Range Adapter for part(1)和Boost Foreach for part(2)。 您不需要编写宏或自己实现迭代器。

#include <map>
#include <string>
#include <boost/range/adaptor/map.hpp>
#include <boost/foreach.hpp>

int main()
{
    // Sample data
    std::map<int, std::string> myMap ;
    myMap[0] = "Zero" ;
    myMap[10] = "Ten" ;
    myMap[20] = "Twenty" ;

    // Loop over map values
    BOOST_FOREACH( std::string text, myMap | boost::adaptors::map_values )
    {
        std::cout << text << " " ;
    }
}
// Output:
// Zero Ten Twenty

===============>>#6 票数:1

你有没有想过使用Boost库 他们实现了一个foreach ,它可能比你要编写的任何东西都更强大......而且还有transform_iterator似乎可以用来做你想要的第二个提取部分。

不幸的是我无法准确地告诉你如何使用它,因为我不太了解C ++ :) 这个Google搜索找到了一些有希望的答案: comp.lang.c ++。moderatedBoost transform_iterator用例

===============>>#7 票数:1

Boost :: For_each是迄今为止最好的选择。 漂亮的是,他们实际给你的是宏BOOST_FOREACH(),然后你可以将它包装和#define到你真正想在代码中调用它的任何东西。 大多数人都会选择好的旧“foreach”,但其他商店可能有不同的编码标准,所以这符合这种心态。 Boost还为C ++开发人员提供了许多其他好东西! 非常值得使用。

===============>>#8 票数:0

我基于Boost foreach代码实现了我自己的foreach_value

#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_VALUE(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( 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)        

例如,您可以在代码中使用它,如下所示:

#define MUNZEKONZA_FOREACH_VALUE foreach_value

std::map<int, std::string> mymap;
// populate the map ...

foreach_value( const std::string& value, mymap ) {
  // do something with value
}

// change value
foreach_value( std::string& value, mymap ) {
  value = "hey";
}

===============>>#9 票数:0

#define zforeach(var, container) for(auto var = (container).begin(); var != (container).end(); ++var)

没有typeof()所以你可以使用这个:

decltype((container).begin()) var 
decltype(container)::iterator var

===============>>#10 票数:0

您可以定义一个模板类,它将mymap的类型作为模板参数,并通过重载*和 - >来充当值的迭代器。

===============>>#11 票数:0

#define foreach(var, container) for (typeof((container).begin()) var = (container).begin(); var != (container).end(); ++var)

C ++中没有typeof ...这对你来说是如何编译的? (它肯定不便携)

  ask by sfink translate from so

未解决问题?本站智能推荐:

2回复

使用gcc或cpp预处理C代码而不解析宏

是否存在我可以传递给这些预处理器之一的标志,导致该预处理器无法解析代码中的任何宏? 我正试图使用​​它只是将所有包含的头文件连接成一个文件。谢谢!
2回复

用gcc编译.cpp

好吧,我偶然做了,使用gcc而不是g ++编译.cpp 但我实际上想要逐行理解控制台输出,如果它有任何意义。 用gcc structpointers.cpp -o structp编译这段代码给出了以下输出:
4回复

如何在GCC中弃用宏?

我知道如何使用不推荐使用的属性来弃用这样的函数: 但是如何弃用这样的宏: 先感谢您。 埃里克
3回复

使用GCC编译.CPP

如何使用GCC编译.c或.cpp文件? 我需要包括一些标准库(fstream,string,iostream)-如何做到这一点? 为了澄清,在这里: (我的.h文件与src文件位于同一目录中)如果使用以下命令:gcc src.cpp -o src.o 我收到很多错误:mem
1回复

Gradle Cpp-Application未在Windows中检测到gcc

我开始更多地使用C ++,并且我也开始学习gradle用作其构建。 我正在使用gradle的cpp-application插件来编译代码。 但是,当我尝试构建它时,gradlew告诉我它无法检测gcc,这是我唯一安装的编译器。 我大部分时间都遵循gradle网站( https://gu
1回复

是否发生段故障取决于gcc编译命令中的cpp顺序?

我编写了一个简单的程序,当定义了新类(例如:One,Two)时,将一个值添加到全局设置容器中: GlobalSet.h GlobalSet.cpp One.h One.cpp Two.h Two.cpp TEST.CPP 但是这个程序
1回复

用g ++链接的预处理器程序类似于gcc中的cpp程序[重复]

这个问题已经在这里有了答案: 有独立的C ++源预处理器吗? [已关闭] 7个答案 我正在读这本书-Brian Gough撰写的GCC简介,他在其中谈论了GNU C预处理程序cpp以及如何将其作为单独的软件包提供,即使它已集成到编译器中。 我想知道是否在g+
1回复

在GCC中实现Borland的__emit__宏

在Borland中,有一个宏__emit__ ,“一个将文字值直接注入目标代码中的伪函数”( James Holderness )。 gcc / g ++是否有等效功能? (我似乎在文档中找不到一个) 如果没有,如何在我的C ++源代码中实现它? 用法可以在“ 变形代码示例
1回复

编译共享库linux gcc / g ++ cpp

我已经成功编译并创建了一个共享库,但是我不确定它是否真正被共享并链接/模拟到DLL。能否告诉我它是否正确? 我已经共享了。h,main.cpp,nameOfLib.cpp。 首先,它是一个真正可共享的图书馆吗? 即使使用nameOfLib.cpp中复杂的cpp代码,它也可以正常工作
1回复

使用g ++ .cpp文件编译gcc .o文件

我有两个文件print_permu.c和gen_permu.cpp 。 我希望将print_permu.c文件编译为目标文件,然后使用该目标文件编译gen_permu.cpp ,该文件包含对print_permu.c的函数的print_permu.c 。 print_permu.c