11

由于for_each接受的函数只接受一个参数(向量的元素),我必须在static int sum = 0 某处定义一个,以便在调用 for_each 后可以访问它。我觉得这很尴尬。有没有更好的方法来做到这一点(仍然使用 for_each)?

#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

static int sum = 0;
void add_f(int i )
{
    sum += i * i;

}
void test_using_for_each()
{
    int arr[] = {1,2,3,4};
    vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    for_each( a.begin(),a.end(), add_f);
    cout << "sum of the square of the element is  " << sum << endl;
}

在 Ruby 中,我们可以这样做:

sum = 0
[1,2,3,4].each { |i| sum += i*i}   #local variable can be used in the callback function
puts sum    #=> 30

您能否展示更多示例for_each在实际编程中通常如何使用(不仅仅是打印出每个元素)?是否可以在 Ruby 中使用for_each模拟“编程模式”,如 map 和注入(或 Haskell 中的 map /fold)。

#map in ruby 
>> [1,2,3,4].map  {|i| i*i} 
=> [1, 4, 9, 16]

#inject in ruby 
[1, 4, 9, 16].inject(0)  {|aac ,i| aac +=i}  #=> 30

编辑:谢谢大家。我从你的回复中学到了很多。我们有很多方法可以在 C++ 中做同样的事情,这使得学习有点困难。但这很有趣:)

4

6 回答 6

50

不,不要使用 std::accumulate() 使用 std::inner_product()。不需要函子。

#include <vector>
#include <numeric>

void main()
{
    std::vector <int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);

    int x = std::inner_product( v1.begin(), v1.end(), v1.begin(), 0 );
}
于 2009-08-25T15:08:10.907 回答
22

使用std::accumulate

#include <vector>
#include <numeric>

// functor for getting sum of previous result and square of current element
template<typename T>
struct square
{
    T operator()(const T& Left, const T& Right) const
    {   
        return (Left + Right*Right);
    }
};

void main()
{
    std::vector <int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);

    int x = std::accumulate( v1.begin(), v1.end(), 0, square<int>() );
    // 0 stands here for initial value to which each element is in turn combined with
    // for our case must be 0.
}

您可以像GMan 的不错的答案那样模拟 std::accumulate ,但我相信使用 std::accumulate 将使您的代码更具可读性,因为它是为此目的而设计的。您可以在此处找到更多标准算法。

于 2009-08-25T04:57:47.837 回答
7

for_each返回(副本)它正在使用的仿函数。所以,像这样:

#include <algorithm>
#include <vector>
#include <iostream>

template <typename T>
class square_accumulate
{
public:
    square_accumulate(void) :
      _sum(0)
      {
      }

      const T& result(void) const
      {
          return _sum;
      }

      void operator()(const T& val)
      {
          _sum += val * val;
      }

private:
    T _sum;
};

int main(void)
{
    int arr[] = {1,2,3,4};
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    int sum = std::for_each(a.begin(), a.end(), square_accumulate<int>()).result();

    std::cout << "sum of the square of the element is " << sum << std::endl;
}

但是,正如其他答案所证明的那样,这std::accumulate是最好的方法。

于 2009-08-25T05:04:05.950 回答
4

不要for_each()为此使用accumulate(),请从<numeric>标题中使用:

#include <numeric>
#include <iostream>
using namespace std;

struct accum_sum_of_squares {
    // x contains the sum-of-squares so far, y is the next value.
    int operator()(int x, int y) const {
        return x + y * y;
    }
};

int main(int argc, char **argv) {
    int a[] = { 4, 5, 6, 7 };

    int ssq = accumulate(a, a + sizeof a / sizeof a[0], 0, accum_sum_of_squares());
    cout << ssq << endl;
    return 0;
}

的默认行为accumulate()是对元素求和,但您可以像我们在这里所做的那样提供自己的函数或仿函数,并且它执行的操作不必是关联的——第二个参数始终是要操作的下一个元素。此操作有时会reduce用其他语言调用。

您可以使用普通函数而不是accum_sum_of_squares仿函数,或者为了更通用,您可以创建accum_sum_of_squares一个接受任何数字类型的类模板。

于 2009-08-25T05:08:06.397 回答
3

作为 STL 此类问题的一般解决方案:您可以传递一个functor- 例如,任何实现operator(). 这比依赖全局变量要好得多,因为所述实例可以保持和更新自己的状态!您可以将其视为一种“编译时鸭子类型”:通用编程不会限制您在该位置传递“函数”,任何“表现得像函数”(即具有适当的operator())的东西都会像出色地!-)

于 2009-08-25T05:04:17.543 回答
3

std::for_each是对每个元素做一些事情。如果你想从所有元素的计算中得到结果,有std::accumulate. 如果您想要 Haskell 的map行为,请使用std::transform.

您可以滥用这三个中的任何一个来做与其他任何一个相同的事情,因为最终它们只是迭代一个迭代器(除了transform' 的形式,它需要两个迭代器作为输入。)关键是它for_each不能替代map/fold - 应该通过 transform/accumulate 来完成 - 尽管 C++ 本身并没有像 Haskell 那样表达 map/fold 概念的东西 - 但 gcc 和 VC++ 都支持 OpenMP,它在#pragma omp parallel for.

Ruby 中的 Inject 更接近于for_each使用成熟的仿函数进行调用,就像上面解释的GMan一样。在 C++0X 中具有变量捕获的 Lambda 函数将使两种语言之间的行为更加相似:

int main(void)
{
    int arr[] = {1,2,3,4};
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    int sum = 0;
    std::for_each(a.begin(), a.end(), [&](int i) { sum += i*i;} );

    std::cout << "sum of the square of the element is " << sum << std::endl;
}
于 2009-08-25T16:04:04.603 回答