在 for_each 上使用仿函数

问题描述 投票:0回答:6

为什么

for_each
对仿函数的调用最后没有更新
sum::total

struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 0;
}
c++ stl functor
6个回答
12
投票

for_each
按值获取仿函数 - 因此它被复制。你可以例如使用一个用指向外部 int 的指针初始化的仿函数。

struct sum
{
    sum(int * t):total(t){};
    int * total;

    void operator()(int element)
    {
       *total+=element;
    }
};

int main()
{
    int total = 0;
    sum s(&total);

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << total << endl; // prints total = 15;
}

或者您可以使用

for_each

的返回值
struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 15;
}

3
投票

for_each
按值接收仿函数的副本。即使在那之后,也可以免费复制它,但会返回副本。

OTOH,您只是在尝试重新发明

std::accumulate
,这将更容易完成工作:

int total = std::accumulate(arr, arr+6, 0);
cout << total << endl; 

3
投票

因为传递给

s
for_each
是按值传递的。
for_each
按价值接受!

在 C++0x 中,你可以用

for_each
解决这个问题,

int sum  = 0;
std::for_each(arr, arr+6, [&](int n){ sum += n; });
std::cout << sum ;

输出:

15

ideone演示:http://ideone.com/s7OOn


或者你可以简单地写在

std::cout
本身:

std::cout<<std::for_each(arr,arr+6,[&](int n)->int{sum += n;return sum;})(0);

奔跑:http://ideone.com/7Hyla

注意这种不同的语法对于学习目的是可以的,关于

std::for_each
如何工作,以及它返回什么,但我推荐在实际代码中使用这种语法。 :-)


在 C++ 中,您可以在仿函数中编写用户定义的转换函数,

struct add
{
    int total;
    add():total(0){};
    void operator()(int element)  {  total+=element;  }
    operator int() { return total ; }
};

int main()
{
    int arr[] = {0, 1, 2, 3, 4, 5};
    int sum = std::for_each(arr, arr+6, add());
    std::cout << sum;
}

它与 Erik 第二个解决方案的版本略有不同:http://ideone.com/vKnmA


0
投票

发生这种情况是因为 std::for_each 要求函子按值传递。 解决方案的解决方法:

struct sum
{
    sum():total(0){};
    int total;
    sum(sum & temp)
    {
        total = temp.total;
    }
    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);  // result of for_each assigned back to s
    cout << s.total << endl; // prints total = 0;
}

0
投票
如果您希望在 std::for_each 之后更新对象状态,

std::ref()
也是另一种选择

struct Sum
{
    int total = 0;
    void operator()(int i) { total += i; }
};

int main()
{
    int arr[] = { 0, 1, 2, 3, 4, 5 };

    Sum obj1;
    Sum t1 = std::for_each(arr, arr + 6, obj1);  // t1.total = 15 
                            // (Note: obj1.total = 0 bcos it is passed by value)

    Sum obj2;
    std::for_each(arr, arr + 6, std::ref(obj2)); // obj2.total = 15 (NO copy)

    Sum t2 = std::for_each(arr, arr + 6, Sum()); // t2.total = 15
}

0
投票

@SridharKritha 是正确的答案,您可以通过传递仿函数的引用来避免复制,这样转换就发生了。 boost库也提到了这个方法。(https://www.boost.org/doc/libs/1_82_0/doc/html/accumulators/user_s_guide.html)

© www.soinside.com 2019 - 2024. All rights reserved.