简体   繁体   English

仿函数在传递给std :: for_each时是否可以保留值?

[英]Can a functor retain values when passed to std::for_each?

According to the first answer to this question, the functor below should be able to retain a value after being passed to foreach ( I couldn't get the struct Accumulator in the example to compile, so built a class). 根据这个问题的第一个答案,下面的仿函数应该能够在传递给foreach之后保留一个值(我无法在示例中获取struct Accumulator进行编译,因此构建了一个类)。

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

Example usage ( as per the example ) 示例用法(根据示例)

// 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 is implemented as a std::deque<Card> . _cards实现为std::deque<Card> No matter how long _cards gets, acc.counter is zero after the for_each completes. 无论_cards获得多长时间,在for_each完成后acc.counter为零。 As I step through in the debugger I can see counter incrementing, however, so is it something to do with acc being passed by value? 当我在调试器中单步执行时,我可以看到计数器递增,但是,它是否与acc通过值传递有关?

This was just asked here . 这只是在这里问的

The reason is that (as you guessed) std::for_each copies its functor, and calls on it. 原因是(正如您猜测的那样) std::for_each复制其仿函数并调用它。 However, it also returns it, so as outlined in the answer linked to above, use the return value for for_each . 但是,它也返回它,因此如上面链接的答案中所述,使用for_each的返回值。

That said , you just need to use std::accumulate : 也就是说 ,你只需要使用std::accumulate

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

A functor and for_each isn't correct here. for_each函数和for_each在这里不正确。


For your usage (counting some, ignoring others), you'll probably need to supply your own functor and use count_if : 对于您的使用(计算一些,忽略其他人),您可能需要提供自己的count_if函数并使用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;

And with C++0x lambda's for fun (just because): 并使用C ++ 0x lambda来获得乐趣(仅仅因为):

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

Much nicer. 好多了。

Yes, it's definitely linked to acc being passed by value. 是的,它肯定与acc通过价值有关。

Modify your accumulator as follows : 修改累加器,如下所示:

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

        int value() { return *counter; }
};

This is because internally the std::for_each() makes a copy of the functor (as it is poassable to pass temporary object). 这是因为std :: for_each()内部生成了仿函数的副本(因为它无法传递临时对象)。 So internally it does do the sum on the copy not on the object you provided. 所以在内部它确实在副本上做了总和而不在你提供的对象上。

The good news is that std::for_each() returns a copy of the functor as a result so you can access it from there. 好消息是std :: for_each()返回了仿函数的副本,因此您可以从那里访问它。

Note: There are other standard algorithms you could use. 注意:您可以使用其他标准算法。 Like std::accumulate(). 像std :: accumulate()。
But suppose this is just a simplified example and you need for_each() to something slightly tricker than the example there are a couple of techniques to allow you access to the accumulator object. 但是假设这只是一个简化的例子,你需要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;

}

Alternatively you can change you Accumalator to increment a reference that is used within the current scope. 或者,您可以更改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;

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM