为什么
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;
}
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;
}
for_each
按值接收仿函数的副本。即使在那之后,也可以免费复制它,但会返回副本。
OTOH,您只是在尝试重新发明
std::accumulate
,这将更容易完成工作:
int total = std::accumulate(arr, arr+6, 0);
cout << total << endl;
因为传递给
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);
注意这种不同的语法对于学习目的是可以的,关于
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
发生这种情况是因为 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;
}
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
}
@SridharKritha 是正确的答案,您可以通过传递仿函数的引用来避免复制,这样转换就发生了。 boost库也提到了这个方法。(https://www.boost.org/doc/libs/1_82_0/doc/html/accumulators/user_s_guide.html)