Embrace the power of negative thinking and start induction with zero instead of one:
auto sum(auto &&val, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val;
else
return val + sum(std::forward<decltype(vals)>(vals)...);
}
The above definition has the side effect that sum(x)
will now compile and return x
. (In fact, you can even make the function work with no arguments, by having it return zero, but then the question arises: zero of which type? To avoid having to go there, I left this case undefined.) If you insist on sum
being defined only from arity 2 upwards, you can use this instead:
auto sum(auto &&val0, auto &&val1, auto &&...vals) {
if constexpr (sizeof...(vals) == 0)
return val0 + val1;
else
return val0 + sum(std::forward<decltype(val1)>(val1),
std::forward<decltype(vals)>(vals)...);
}
However, you should probably allow the ‘vacuous’ case whenever it makes sense to do so: it makes for simpler and more general code. Notice for example how in the latter definition the addition operator appears twice: this is effectively duplicating the folding logic between the two cases (in this case it’s just one addition, so it’s relatively simple, but with more complicated operations it might be more burdensome), whereas handling the degenerate case is usually trivial and doesn’t duplicate anything.
(I omitted concept annotations, as they do not seem particularly relevant to the main problem.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…