我有一个'foreach'宏我经常使用C++的工作对于大多数STL容器:

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

(注意,'类型的'是一个海湾合作委员会延长。) 它是用这样的:

std::vector< Blorgus > blorgi = ...;
foreach(blorgus, blorgi) {
  blorgus->draw();
}

我想让类似的东西,迭代地图的价值观。叫它"foreach_value",也许。因此,不是写作

foreach(pair, mymap) {
  pair->second->foo();
}

我会写

foreach_value(v, mymap) {
  v.foo();
}

我不能拿出一个宏观,将做到这一点,因为它要求宣布两个变量:迭代和价值变量(v,上文)。我不知道如何去做,在初始化的循环,即使使用的海湾合作委员会的扩展。我可以声明它之前刚刚foreach_value呼吁,但随后它将与冲突的其他实例foreach_value宏在同一范围。如果我可以的后缀当前的行号的迭代变量名称,它的工作,但我不知道如何做到这一点。

有帮助吗?

解决方案

你可以做这种使用两个循环。第一个宣布的迭代,一个名称,这是一个功能的容器变量(以及可以让这个丑陋的如果你在担心有关冲突与自己的代码)。第二个宣布的价值变量。

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

通过使用相同的循环终止的条件,外循环只会发生一次(并且如果你幸运的话,得到优化掉).还有,你避免的电话->第二次迭代,如果地图上是空的。这是同样的原因,三算中增加的内循环;最后,我们只是离开var在最后价值,因为它不会被引用了。

你可以联ci(集装箱),但我认为它使宏更具可读性。

其他提示

你将会寻找 BOOST_FOREACH -他们已经做了所有工作你了!

如果你想滚你自己,你可以宣布一块在任何地方C++,这可以解决你的范围问题与你的中间储存的itr->第二 ...

// 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
}

STL 变换 功能也做了类似的东西。

这些参数是(按顺序):

  1. 输入迭代的指定开始的一个容器
  2. 输入迭代指定的端的容器
  3. 一个输出迭代定义放在哪里的输出(对于就地改变,类似于对每一个,只是通过输入迭代#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"
}

或者还有 累积 功能,即允许某些价值观可以保留之间的电话的功能物体。 累积 不会修改的数据在输入容器的情况 变换.

你有没有想过使用 提高图书馆?他们有一个 foreach 宏实施 这是可能更强大,比任何东西,你会写...还有 transform_iterator 这似乎可以被用来做二提取一部分的你想要什么。

不幸的是,我不能确切地告诉你 如何 使用它,因为我不知道够不够C++:) 这个谷歌搜索 变成了一些有希望的答案: comp.郎。c++。主持, 提高transform_iterator使用情况.

提升::For_each是到目前为止你最好的选择。俏皮的事情是什么,他们实际上给你是的宏BOOST_FOREACH()然后你就可以包装和定义的任何你真喜欢叫它在你的代码。大多数人将选择良好古老的"foreach",但其他商店里可能有不同的编码标准,因此适合这种心态。提高还有很多其他东西用C++开发!值得使用。

我创建了一个小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版本的检查,删除的内的循环、地方变量版

他们肯定做的工作对我来说,我希望他们也将让你的生活更容易一点:)

有两个部分这个问题。你需要以某种方式(1)产生的一个迭代(或者说,可迭代顺序)过你的地图 (不钥匙),以及(2)使用宏做的迭代,没有太多的样板。

干净的解决方法是使用一个 提高范围 适配器 对于部分(1)和 提高Foreach 对于一部分(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

你可以定义的模板类需要的类型的mymap作为一个模板参数,并就像一个迭代过值超载*和->.

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

有没有类型的用C++...这是如何编写给你?(这当然不是便携式)

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

#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";
}
#define zforeach(var, container) for(auto var = (container).begin(); var != (container).end(); ++var)

没有类型()所以你可以用这样的:

decltype((container).begin()) var 
decltype(container)::iterator var
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top