我总是尝试在任何地方使用STL算法,而不是编写手动循环。但是,我很难理解std::accumulate
通常如何有用。每当我需要计算总和或平均值时,我几乎总是求助于手动循环,因为我很难让std::accumulate
做我需要的东西。
问题是我很少有一个简单的整数向量需要求和。通常,我想使用特定的成员变量对一个对象数组求和。是的,我知道有std::accumulate
的版本采用BinaryFunction,但我看到的问题是这个函数需要采用T
类型的两个值,其中T
是类型 sum 的内容,而不是操作数的类型。我无法理解这是如何有用的。
考虑一个我认为很常见的案例。我有以下课程:
struct Foo
{
Foo(int cost_, int id_) : cost(cost_), id(id_)
{ }
int cost;
int id;
};
现在,假设我想使用Foo
计算Foo::cost
个对象数组的总和。
我想说:
std::vector<Foo> vec;
// fill vector with values
int total_cost = std::accumulate(vec.begin(), vec.end(), 0, sum_cost);
sum_cost
定义为:
int sum_cost(const Foo& f1, const Foo& f2)
{
return f1.cost + f2.cost;
}
问题是,这不起作用,因为std::accumulate
需要一个BinaryFunction,它接收结果总和类型的两个实例 - 在这种情况下只是int
。但这对我有什么用呢?如果我的BinaryFunction接收两个int
,我无法指定我想要对cost
字段求和。
那么,std::accumulate
为什么这样设计呢?我在这里看不到明显的东西吗?
答案 0 :(得分:18)
你对累积运算符采用两种相同类型的错误。只有你愿意,它才会这样做。运算符的使用具体为sum = op(sum, *iter)
。因此你的代码:
int count = std::accumulate(stuff.begin(), stuff.end(), 0, [](int current_sum, stuff_value_t const& value) { return current_sum + value.member; });
如果你不能使用lambda,那么当然你使用标准的绑定器或boost :: bind。
答案 1 :(得分:4)
使用仿函数:
class F { // sum Foos
F(int init = 0);
template<class T>
Foo operator()(const Foo &a, const T &b) const;
operator int() const;
};
int total_cost = std::accumulate(vec.begin(), vec.end(), F(0), F());
注意你也可以做其他事情:
class F { // sum foo values members
template<class T>
T operator()(const T &a, const Foo &b) const;
};
int total_cost = std::accumulate(vec.begin(), vec.end(), int(0), F());