Instead of writing your own loop for summing up the vector, you should use std::accumulate
(like Walter suggested), but - don't pass a vector reference, even if it's just a const
.
Let's take inspiration from std::accumulate
's interface:
template <class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init);
And write something like:
template <typename InputIt, typename Result = double>
Result average(InputIt start, InputIt end)
{
static_assert(
std::is_arithmetic<std::decay_t<decltype(*start)>>::value,
"Can only average arithmetic values");
return static_cast<Result>(
std::accumulate(start, end, static_cast<Result>(0)) /
std::distance(start, end)
);
}
Notes:
- I don't like
first
and last
, since last
is not really the last, it's one past the last element; so I use start
and end
instead.
- If you were using C++20, you could constraint the templates themselves; and you could also consider std::reduce instead of
std::accumulate
.
And if you want a function to call for a container, write that too:
template <typename Container, typename Result = double>
Result average(const Container& c)
{
using const_iter = typename Container::const_iterator;
return average<const_iter, Result>(std::cbegin(c), std::cend(c));
}
... and if you're in C++20, you could instead write this for a range rather than an arbitrary type.
See this running on GodBolt.