Вы делаете ошибочное предположение: этот тип T
того же типа, что и InputIterator
.
Но std::accumulate
является общим и допускает всевозможные творческие накопления и сокращения.
Пример №1: Накопление заработной платы по всем сотрудникам
Вот простой пример: класс Employee
с множеством полей данных.
class Employee {
/** All kinds of data: name, ID number, phone, email address... */
public:
int monthlyPay() const;
};
Вы не можете осмысленно «накапливать» набор сотрудников. Это бессмысленно; это не определено. Но вы можете определить накопление в отношении сотрудников. Допустим, мы хотим просуммировать всю ежемесячную заработную плату всех сотрудников. std::accumulate
может это сделать:
/** Simple class defining how to add a single Employee's
* monthly pay to our existing tally */
auto accumulate_func = [](int accumulator, const Employee& emp) {
return accumulator + emp.monthlyPay();
};
// And here's how you call the actual calculation:
int TotalMonthlyPayrollCost(const vector<Employee>& V)
{
return std::accumulate(V.begin(), V.end(), 0, accumulate_func);
}
Итак, в этом примере мы накапливаем int
значение в коллекции из Employee
объектов. Здесь сумма накопления не того же типа переменной, по которой мы фактически суммируем.
Пример № 2: Накопление среднего
Вы также можете использовать accumulate
для более сложных типов накоплений - возможно, захотите добавить значения к вектору; возможно, у вас есть какая-то загадочная статистика, которую вы отслеживаете по входным данным; и т. д. То, что вы накапливаете, не должно быть просто числом; это может быть что-то более сложное.
Например, вот простой пример использования accumulate
для вычисления среднего значения вектора целых чисел:
// This time our accumulator isn't an int -- it's a structure that lets us
// accumulate an average.
struct average_accumulate_t
{
int sum;
size_t n;
double GetAverage() const { return ((double)sum)/n; }
};
// Here's HOW we add a value to the average:
auto func_accumulate_average =
[](average_accumulate_t accAverage, int value) {
return average_accumulate_t(
{accAverage.sum+value, // value is added to the total sum
accAverage.n+1}); // increment number of values seen
};
double CalculateAverage(const vector<int>& V)
{
average_accumulate_t res =
std::accumulate(V.begin(), V.end(), average_accumulate_t({0,0}), func_accumulate_average)
return res.GetAverage();
}
Пример № 3: Накопление скользящего среднего
Еще одна причина, по которой вам нужно начальное значение, заключается в том, что это значение не всегда является значением по умолчанию / нейтральным для вычислений, которые вы делаете.
Давайте возьмем средний пример, который мы уже видели. Но теперь нам нужен класс, который может удерживать текущее среднее значение, то есть мы можем продолжать вводить новые значения и проверять среднее на данный момент по нескольким вызовам. .
class RunningAverage
{
average_accumulate_t _avg;
public:
RunningAverage():_avg({0,0}){} // initialize to empty average
double AverageSoFar() const { return _avg.GetAverage(); }
void AddValues(const vector<int>& v)
{
_avg = std::accumulate(v.begin(), v.end(),
_avg, // NOT the default initial {0,0}!
func_accumulate_average);
}
};
int main()
{
RunningAverage r;
r.AddValues(vector<int>({1,1,1}));
std::cout << "Running Average: " << r.AverageSoFar() << std::endl; // 1.0
r.AddValues(vector<int>({-1,-1,-1}));
std::cout << "Running Average: " << r.AverageSoFar() << std::endl; // 0.0
}
Это тот случай, когда мы полностью полагаемся на возможность установить это начальное значение для std::accumulate
- нам нужно иметь возможность инициализировать накопление с разных начальных точек.
Таким образом, std::accumulate
подходит для любого случая, когда вы выполняете итерацию по входному диапазону и создаете один единственный результат в этом диапазоне. Но результат не обязательно должен быть того же типа, что и диапазон, и вы не можете делать никаких предположений о том, какое начальное значение использовать - вот почему у вас должен быть начальный экземпляр для использования в качестве результата накопления.
person
Ziv
schedule
18.02.2015
accumulate(V.begin()+1, V.end(), V.begin());
не работает, еслиV
пусто. - person verdesmarald   schedule 28.09.2012