Why do std::numeric
algorithms seem to prefer op instead of op=? For example, here is the implementation of std::accumulate
in LLVM:
template <class _InputIterator, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
_Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
for (; __first != __last; ++__first)
__init = __init + *__first;
return __init;
}
Would this not be potentially more efficient/less verbose/better if implemented using the +=
operator?
The standard is defined in terms of +
, not +=
:
26.7.2 Accumulate
[accumulate]
template <class InputIterator, class T> T accumulate(InputIterator first, InputIterator last, T init); template <class InputIterator, class T, class BinaryOperation> T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op);
Effects: Computes its result by initializing the accumulator
acc
with the initial valueinit
and then modifies it withacc = acc + *i
or acc = binary_op(acc, *i)
for every iteratori
in the range[first,last)
in order.
Same holds for other numerical algorithms.
But that's the reason why they're implemented like this nowadays. However, to learn about the original reason, one needs to go further down the rabbit hole:
Requirements on types
For the first version, the one that takes two arguments:
InputIterator
is a model of Input Iterator.T
is a model of Assignable.- If
x
is an object of typeT
andy
is an object ofInputIterator
'svalue
type, thenx + y
is defined.- The return type of
x + y
is convertible toT
.
So, why is that? Lets ask Alexander Stepanov, the mind behind STL:
[A] user has asked a [question] on StackOverflow two days ago concerning the implementation and formulation of numerical algorithms like
accumulate
orinner_product
, which are defined in terms of+
instead of+=
(section 26.7 in ISO C++11).I've tried to find some rationale behind the decision, but even the version on SGI's page doesn't mention anything regarding this particular choice of the operator.
Was the choice of the operator (a = a + b instead of a += b) only based on your personal preference, as some comments assume? Was a+b the more natural way to write the operation back then? Or was it simply a matter of symmetry between a = a +b and a = bin_op(a,b)?
-- [Zeta]
Now, before you read his answer, remember that he started to write a generic library about ~30 years ago, and his and Meng Lee's initial document The Standard Template Library will have its twenty years anniversary this October. Without further ado, I present his answer:
I suspect that it was a matter of symmetry between a = a + b and a = bin_op(a,b), but I really do not remember. I should have written a rationale document stating all the reasoning between different design choices in STL, but I did not. Sorry.
(If Stepanov reads this by any chance: thanks again for your answer!)
I personally believe that the inspiration by Common Lisp's reduce
has been another factor, but that's just speculation.
Sometimes, decision in a standard are based on personal preference and elegance. For example, if Stroustrup had written the STL, he would have "strongly prefer[ed] the use of a+=b as being a more direct expression of intent and typically faster than a=a+b". However, I have to admit that the symmetry between a = a+b and a=bin_op(a,b) has its own beauty.
That being said, this a+=b
and a=a+b
controversy will promote challenges:
This issue will become very important when we define standard concepts, and I do not know how it will be resolved. [Stroustrup; also thanks to him for answering my question!]
That's all, I hope you've enjoyed the ride through a little bit of C++ history.
It might be more efficient, and would clearly be less verbose.
The usual reason for doing things this way is to minimize the requirements on the underlying type. If you used +=
, then the underlying type would have to support +=
. For something like int
that's trivial and already present, but for a class you define, it's entirely possible would define +
and =
, but not the compound +=
(in which case, code that used +=
would obviously fail).
In my opinion the main reason is that you could use standard functional object std::plus
and get the same result as with operator +
the same way as using operator <
and standard functional object std::less
in sorting algorithms like std::sort
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With