如何使用带有参数/修改的 std::foreach

Posted

技术标签:

【中文标题】如何使用带有参数/修改的 std::foreach【英文标题】:How to use std::foreach with parameters/modification 【发布时间】:2009-01-24 18:53:23 【问题描述】:

我发现自己在写作

for(int i=0;i<myvec.size();i++)
   myvec[i]->DoWhatever(param);

很多,我想将其压缩成foreach 语句,但我不确定如何在不冗长的情况下将param 放入其中。我也有类似的东西

for(int i=0;i<myvec.size();i++)
   if(myvec[i]->IsOK())
      myvec[i]->DoWhatever(param);

我也想重写那个人。有什么想法吗?

哦,还有,由于种种原因,我不想用boost。

【问题讨论】:

【参考方案1】:
#include <vector>
#include <algorithm>
#include <functional>

class X

    public:
        void doWhat(int x) 
        bool IsOK() const return true;
;
class CallWhatIfOk

    public:
        CallWhatIfOk(int p): param(p) 

        void operator()(X& x) const
           if (x.IsOK())    x.doWhat(param);
    private:
        int param;
;

int main()

    std::vector<X>      myVec;

    std::for_each(  myVec.begin(),
                    myVec.end(),
                    std::bind2nd(std::mem_fun_ref(&X::doWhat),4)
                 );


    std::for_each(  myVec.begin(),
                    myVec.end(),
                    CallWhatIfOk(4)
                 );

【讨论】:

【参考方案2】:

哦,还有,由于种种原因,我不想用boost。

有效的决定,但很可能是错误的决定。将 Boost 视为 STL 的扩展。 C++ 是一种库驱动的语言。如果不考虑到这一点,你的代码会质量较差。

虽然可以在此处使用std::for_each,但在 C++0x 之前 C++ 中没有 lambda 表达式使得这变得乏味。我提倡使用Boost.ForEach!它使这变得更容易

foreach (yourtype x, yourvec)
    if (x.IsOK())
        x.Whatever();

【讨论】:

唉,是否使用 boost 不是我的决定。 可能想说你不能使用 boost。说你不想想要只是在要求一个论点......;)【参考方案3】:

我首选的解决方案通常是编写一个仿函数来做我需要的事情:

struct doWhatever 
  doWhatever(const Param& p) p(p) 
  void operator(MyVec v&, Param p) 
    v.DoWhatever(param);
  

private:
  Param p;
;

然后循环:

std::for_each(myvec.begin(), myvec.end(), doWhatever(param));

根据您有多少变体,这可能有点过于冗长。 不过,有很多选项可以内联。 boost::lambda 可以让你在调用点构造你需要的函数。 boost::bind(或标准库绑定函数)可以让您将参数 param 绑定到函数,因此您无需每次都将其作为参数提供。

boost::lambda 可能是最简洁灵活的方法。我通常使用普通函子方法,因为语法更容易记住。 ;)

【讨论】:

这是我所拥有的(并希望避免):) 嗯,没有提升(哎哟),我不认为你可以做的更短。在某些情况下, std::bind_* 东西可能会对您有所帮助,但没有任何灵丹妙药。 (至少在 c++0x 之前加上 lambda 表达式)【参考方案4】:

当我们有支持 C++0x lambda 表达式的编译器时,这将变得简单且微创:

std::for_each(myvec.begin(),myvec.end(),[&](X& item)
     item->DoWhatever(param);
);

第二个例子可能是这样的:

std::for_each(myvec.begin(),myvec.end(),[&](X& item)   
   if(item->IsOK())      
      myvec[i]->DoWhatever(param);
);

【讨论】:

太可惜了,它不适用于 g++ :(。我希望在某些时候我能够使用这些结构......【参考方案5】:
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/lambda/if.hpp>
#include <boost/lambda/bind.hpp>


struct A

  bool IsOK ()  return true; 
  void DoWhatever (int param) 
;

struct B

  bool IsOk (A * a)  return true; 
  void DoWhatever (A * a, int param) 
;

typedef std::vector<A *> Myvec;

void main()

  Myvec myvec;
  int param = 1;
  B b;

  // first challenge using boost::bind (fnct in the same class)
  std::for_each (myvec.begin(), myvec.end(),
    boost::bind (&A::DoWhatever, _1, param));

  // first challenge using boost::bind (fnct in an external class)
  std::for_each (myvec.begin(), myvec.end(),
    boost::bind (&B::DoWhatever, &b, _1, param));

  // second challange using boost::lambda (fnct in the same class)
  std::for_each (myvec.begin(), myvec.end(),
    boost::lambda::if_then(
      boost::lambda::bind (&A::IsOK, boost::lambda::_1), 
      boost::lambda::bind (&A::DoWhatever, boost::lambda::_1, param)
    )
  );

  // second challange using boost::lambda (fnct in an external class)
  std::for_each (myvec.begin(), myvec.end(),
    boost::lambda::if_then(
      boost::lambda::bind (&B::IsOK, &b, boost::lambda::_1), 
      boost::lambda::bind (&B::DoWhatever, &b, boost::lambda::_1, param)
    )
  );


您可以使用命名空间来简化它...

【讨论】:

【参考方案6】:

如果您使用的是 GCC,您可以定义如下内容:

#define foreach(element, array) \
    for(typeof((array).begin()) element = (array).begin(), __end_##element = (array).end();\
        element != __end_##element;\
        ++element)

然后像这样使用它:

foreach(element, array)
    element->DoSomething(); //or (*element)->DoSomething() if type is already a pointer

我在自定义数组上使用它,但它也适用于 std::vector。

【讨论】:

以上是关于如何使用带有参数/修改的 std::foreach的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 in 参数直接调用带有 ref 参数的方法

如何使用 JNI 从 JAVA 调用带有 C++ 参数的函数?

如何从 IIS 重定向带有参数的 URL

oracle中怎么执行带有输出参数的存储过程,在程序中我知道怎么调用,

oracle中怎么执行带有输出参数的存储过程,在程序中我知道怎么调用,

如何在 argparse 中使用带有 nargs='*' 参数的可选位置参数?