Вместо того, чтобы выполнять редактирование, чтобы гарантировать, что ваши итераторы ссылаются на списки одного типа, вам гораздо лучше написать код в качестве универсального алгоритма с типом итератора в качестве параметра шаблона.
Я бы также отметил, что для std::list
, оба ваших исходных кода и , большинство опубликованных ответов имеют довольно серьезную проблему эффективности: учитывая типичную реализацию списка, они повторяют список один раз сложить значения, а затем сделать это снова, чтобы посчитать количество элементов. Теоретически, list.size()
может работать в постоянном времени без итерации элементов, но на самом деле это редко имеет место (вы можете иметь постоянную сложность для list::size()
или list::splice
, но не для обоих в один раз).
Я бы написал код примерно так:
template <class fwdit>
typename fwdit::value_type arithmetic_mean(fwdit begin, fwdit end) {
typedef typename fwdit::value_type res_type;
res_type sum = res_type();
size_t count = 0;
for (fwdit pos = begin; pos!= end; ++pos) {
sum += *pos;
++count;
}
return sum/count;
}
Это общее, так что оно продолжит работать (без изменений), когда вы поймете, что std::list
был плохим выбором, и вам действительно было бы лучше с std::vector
. Точно так же, если вы хотите получить среднее арифметическое некоторых int вместо double, оно может справиться и с этим (опять же, без изменения кода). В-третьих, даже если (как предложено выше) реализация вашей библиотеки st::list::size()
окажется линейной, она все равно будет проходить по списку только один раз, так что, скорее всего, она будет примерно в два раза быстрее (рабочей версии) исходного кода.
Конечно, кеширование может (будет) влиять на это - когда вы усредняете небольшой список, первый обход перетянет весь список в кеш, поэтому второй обход обычно будет намного быстрее (поэтому устраняется второй обход) не сэкономит столько времени).