Reputation: 131
In the boost library, we use accumulators like this:
acc(1); // push things into acc
cout << max( acc ) << endl; // get its result
Why can't we define its interface like this:
acc.push(1);
cout << acc.max() << endl;
So why do the accumulators from the boost library have a function-like interface? What is the advantage of it?
Upvotes: 2
Views: 242
Reputation: 11143
Here are two reasons:
You can pass them to algorithms, such as for_each
:
acc = std::for_each(range.begin(), range.end(), acc);
This gives all accumulators a uniform interface. This is helpful to combine them eg. with accumulator_set
.
Upvotes: 1
Reputation: 41962
Here's my guess
The reason that operator ()
is used for pushing instead of push()
is because acc(value)
reads "accumulate another value" which sounds more natural than acc.push(value)
which is "push a value to the accumulator"
Besides the accumulator can receive optional features like covariate or weight and that way probably the result looks and sounds better than acc.push(value, feature)
. Some examples from the documentation:
acc( 1.2, covariate1 = 12 );
acc( 2.3, covariate1 = -23 );
acc( 3.4, covariate1 = 34 );
acc( 4.5, covariate1 = -45 );
acc(1, weight = 2); // 1 * 2
acc(2, weight = 4); // 2 * 4
acc(3, weight = 6); // + 3 * 6
acc(1, weight = 2, covariate1 = 3);
acc(0, weight = 4, covariate1 = 4);
acc(2, weight = 9, covariate1 = 8);
And then max(acc)
is used instead of acc.max()
because it allows extensibility while still maintaining consistency. By writing a new function that receives an accumulator you'll be able to do other things to the accumulated list
std::cout << "Mean: " << mean(acc) << std::endl;
std::cout << "Moment: " << accumulators::moment<2>(acc) << std::endl;
If a member method was used then there'll only be a limited number of default operations like acc.mean()
, acc.max()
, the remaining things must be used like a function such as product(acc)
, rolling_moment<2>(acc)
, kurtosis(acc)
, skewness(acc)
... which breaks consistency
Upvotes: 0