Для домашнего задания я должен создать шаблонную функцию стандартного отклонения, которая может быть выполнена в любом контейнере. Вот что у меня есть:
template <typename Container>
double findMean(Container c, int count){
double sum = 0;
for (auto&& e : c){
sum += e;
}
sum /= count;
return sum;
}
template <typename Container>
double findStDev(Container c){
double mean = findMean(c, c.size());
std::cout << mean << std::endl;
for (auto&& e : c){
e -= mean;
e *= e;
}
mean = sqrt(findMean(c, c.size()));
return mean;
}
В первый раз я нахожу среднее значение, которое хочу разделить на полный размер контейнера (n), но когда я нахожу его во второй раз для стандартного отклонения, мне нужно разделить на размер-1 (n-1).
Доступна ли функция .size () для всех контейнеров c ++?
Почти. Согласно таблице 96 — требования к контейнерам в N3797, все контейнеры в стандартной библиотеке должны обеспечивать функцию-член size
, Он должен иметь постоянное время выполнения и возвращать значение distance(a.begin(),a.end())
для контейнера a
,
Однако, есть одно (и только одно) исключение, упомянутое позже:
Forward_list удовлетворяет всем требованиям контейнера (таблица 96), за исключением того, что член size ()
функция не предусмотрена.
(N3797 23.3.4.1, пункт 2)
Это означает, что std::forward_list
действительно стандартный контейнер, который делает не иметь функцию-член size
,
В старой доброй традиции STL ваш шаблон может принимать пару прямых итераторов и подсчитывать расстояние при суммировании элементов.
#include <cstddef>
#include <iterator>
template<typename FwdIter,
typename value_type = typename std::iterator_traits<FwdIter>::value_type>
value_type
mean(const FwdIter begin, const FwdIter end)
{
std::size_t count {0};
value_type sum {};
for (auto it = begin; it != end; ++it)
{
sum += *it;
++count;
}
return sum / count;
}
Это будет работать для стандартных библиотечных контейнеров, массивов, указателей, что угодно. Для контейнеров вы можете просто определить удобный шаблон переадресации, который вызывает cbegin
а также cend
если ты хочешь.
Обратите внимание, что я исключил любые ограничения типов из приведенного выше примера. На практике, вы должны, вероятно, std::enable_if
шаблон только при особых условиях, таких как, если std::is_arithmetic<value_type>
,
Все ли контейнеры имеют функцию .size ()?
Нет. Большинство из них делают, и до C ++ 11, все они сделали. Однако в C ++ 11 появился шаблон класса односвязных списков. std::forward_list
, который не иметь size()
функция-член. Все остальные контейнеры делают, и текущий стандарт определяет, что алгоритмическая сложность равна O (1). Pre-C ++ 11, std::list
было разрешено иметь линейную сложность.