函子在传递给 std::for_each 时可以保留值吗?

发布于 2024-08-18 08:19:14 字数 873 浏览 14 评论 0原文

根据这个问题的第一个答案,下面的函子应该能够在之后保留一个值被传递给 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。无论 _cards 持续多久,for_each 完成后 acc.counter 都为零。然而,当我在调试器中单步执行时,我可以看到计数器递增,那么这与按值传递 acc 有关吗?

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).

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>. No matter how long _cards gets, acc.counter is zero after the for_each completes. 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁把谁当真 2024-08-25 08:19:14

这只是此处询问

原因是(正如您所猜测的)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 lambda 来娱乐(只是因为):

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

更好。

This was just asked here.

The reason is that (as you guessed) std::for_each copies its functor, and calls on it. However, it also returns it, so as outlined in the answer linked to above, use the return value for for_each.

That said, you just need to use std::accumulate:

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

A functor and for_each isn't correct here.


For your usage (counting some, ignoring others), you'll probably need to supply your own functor and use 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):

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

Much nicer.

虫児飞 2024-08-25 08:19:14

是的,它肯定与按值传递的 acc 相关。

按如下方式修改您的累加器:

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

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

Yes, it's definitely linked to acc being passed by value.

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; }
};
睫毛上残留的泪 2024-08-25 08:19:14

这是因为 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;

}

或者,您可以更改累加器以增加当前范围内使用的引用。

#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;

}

This is because internally the std::for_each() makes a copy of the functor (as it is poassable to pass temporary object). 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.

Note: There are other standard algorithms you could use. Like 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.

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

#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;

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文