3

この質問に対する最初の回答によると、以下のファンクターはに渡された後も値を保持できるはずですforeach(例ではコンパイルできなかったためstruct Accumulator、クラスを作成しました)。

class Accumulator
{
    public:
        Accumulator(): counter(0){}
        int counter;
        void operator()(const Card & c) { counter += i; }
};

使用例(例に従って)

// Using a functor
Accumulator acc;
std::for_each(_cards.begin(), _cards.end(), acc);
// according to the example - acc.counter contains the sum of all
// elements of the deque 

std::cout << acc.counter << std::endl;

_cardsとして実装されますstd::deque<Card>。どれだけ長く_cardsacc.counterも、完了後はゼロになりfor_eachます。デバッガーをステップスルーすると、カウンターの増分が表示accされますが、値が渡されることと関係がありますか?

4

3 に答える 3

6

これはちょうどここで尋ねられました

その理由は、(ご想像のとおり)std::for_eachそのファンクターをコピーして呼び出すためです。ただし、それも返すので、上記のリンク先の回答で概説されているように、の戻り値を使用しますfor_each

そうは言っても、あなたはただ使う必要がありますstd::accumulate

int counter = std::accumulate(_cards.begin(), _cards.end(), 0);

ファンクターであり、for_eachここでは正しくありません。


あなたの使用法(いくつかを数え、他を無視する)のために、あなたはおそらくあなた自身のファンクターを供給して使用する必要があるでしょうcount_if

// unary_function lives in <functional>
struct is_face_up : std::unary_function<const Card&, const bool>
{
    const bool operator()(const card& pC) const
    {
        return pC.isFaceUp(); // obviously I'm guessing
    }
};

int faceUp = std::count_if(_cards.begin(), _cards.end(), is_face_up());
int faceDown = 52 - faceUp;

そして、楽しみのためにC ++ 0xラムダを使用すると(理由だけで):

int faceUp = std::count_if(_cards.begin(), _cards.end(),
                            [](const Card& pC){ return pC.isFaceUp(); });

はるかに良い。

于 2010-01-20T14:59:57.190 に答える
3

はい、それは間違いなく、値によって渡されるaccにリンクされています。

アキュムレータを次のように変更します。

class Accumulator
{
    public:
        Accumulator(): counter(new int(0)){}
        boost::shared_ptr<int> counter;
        void operator()(int i) { *counter += i; }

        int value() { return *counter; }
};
于 2010-01-20T14:53:51.950 に答える
3

これは、内部的にstd :: for_each()がファンクターのコピーを作成するためです(一時オブジェクトを渡すことができるため)。したがって、内部的には、提供したオブジェクトではなく、コピーに対して合計を実行します。

幸いなことに、std :: for_each()は結果としてファンクターのコピーを返すため、そこからアクセスできます。

注:使用できる標準のアルゴリズムは他にもあります。std :: accumulate()のように。
ただし、これは単純化された例であり、例よりも少しトリッキーなfor_each()が必要であると仮定します。アキュムレータオブジェクトにアクセスできるようにするためのテクニックがいくつかあります。

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

class Card{ public: int i;};
class Accumulator
{
    public:
        Accumulator(): counter(0){}
        int counter;
        void operator()(const Card & c) { counter += c.i; }
};


int main()
{
    std::vector<Card>   cards;

    Accumulator a = std::for_each(cards.begin(), cards.end(), Accumulator());

    std::cout << a.counter << std::endl;

}

または、Accumalatorを変更して、現在のスコープ内で使用されている参照をインクリメントすることもできます。

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

class Card{ public: int i;};
class Accumulator
{
        int&  counter;
    public:
        // Pass a reference to constructor.
        // Copy construction will pass this correctly into the internal object used by for_each
        Accumulator(int& counterRef): counter(counterRef){}
        void operator()(const Card & c) { counter += c.i; }
};


int main()
{
    std::vector<Card>   cards;

    int counter = 0;  // Count stored here.

    std::for_each(cards.begin(), cards.end(), Accumulator(counter));

    std::cout << counter << std::endl;

}
于 2010-01-20T15:27:58.233 に答える