11

for_eachで受け入れられる関数は、1つのパラメーター(ベクトルの要素)のみを受け取るため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(各要素を印刷するだけでなく)実際のプログラミングで通常どのように使用されるかについて、他の例を示していただけますか?for_eachマップのような「プログラミングパターン」をシミュレートし、Ruby(またはHaskellではマップ/フォールド)で注入することは可能ですか?

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

std :: accumulateは、素晴らしいGManの答えのようにエミュレートできますが、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()要素を合計することですが、ここで行うように独自の関数またはファンクターを提供でき、それが実行する操作は結合である必要はありません。2番目の引数は常に操作される次の要素です。この操作は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ください。

これら3つのいずれかを悪用して、他のいずれかと同じことを行うことができます。これは、最終的にはイテレーターを反復処理するだけだからです(transform2つのイテレーターを入力として受け取るフォームを除く)。ポイントはfor_each、 map/fold-これはtransform/accumulateによって実行する必要があります-C++にはHaskellのようにmap/foldの概念を表現するものがネイティブにありませんが、gccとVC++の両方がOpenMPをサポートしてい#pragma omp parallel forます。

Rubyでのインジェクトは、上で説明したGManfor_eachのように、本格的なファンクターを使用した呼び出しに非常によく似ています。C ++ 0Xで変数キャプチャを使用するLambda関数は、2つの言語間の動作をさらに類似させます。

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 に答える