在 for_each 中使用函数对象

8
为什么对于函数对象的 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;
}
5个回答

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 通过值传递方式接收你的函数对象的副本。尽管如此,它仍然可以复制该对象,但返回的是其副本。

另一方面,你只是试图重新发明 std::accumulate,它可以更轻松地完成这项工作:

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

3

因为你传递给 for_eachs 是按值传递的。 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::ref() 是另一个选项,如果您希望在 std::for_each 后更新对象状态。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接