Почему C++ не стандартизировал перегрузки алгоритмов, которые работают со всеми контейнерами?

Стандартный ISO C++ имеет богатую библиотеку алгоритмов, включая множество синтаксического сахара, например std::max_element, std::fill, std::count, и т.д.

Мне трудно понять, почему ISO счел нужным стандартизировать многие такие тривиальные алгоритмы, но не перегружать алгоритмы, которые работают с целыми контейнерами.

Я действительно не понимаю, почему они добавили такие базовые вещи, когда у нас остались версии целых контейнеров (безусловно, наиболее распространенный случай) или аналогичным образом осталось злодеяние, которое является идиомой векторного стирания-удаления:

v.erase(std::remove(v.begin(), v.end(), elem), v.end());

Кажется, что в каждый проект, который я пишу на C++, я включаю свой собственный файл заголовка, который включает базовый синтаксический сахар для таких вещей.

Конечно, в настраиваемый заголовок можно включить любую из тривиальных перегрузок всего контейнера. То же верно и для многих стандартизированных простых алгоритмов.

Я пытаюсь понять, почему в стандарте есть веская причина для таких вещей, как std::max_element и std::fill для диапазонов, но не для версий, которые работают с целыми контейнерами, или для другого синтаксического сахара, уменьшающего многословность написания кода C++.

2 ответа

Почему C++ не стандартизировал перегрузки алгоритмов, которые работают со всеми контейнерами?

Ответ такой же, как и на все вопросы вроде этого: такие перегрузки не стандартизированы либо потому, что такое изменение не было предложено, либо потому, что такое предложение не было принято. В оригинальном STL таких перегрузок не было.

Ответ на подобный вопрос ссылки на блог, который имеет аргумент, почему такая перегрузка будет проблематична для некоторых алгоритмов, которые могут быть одной из причин, почему такие перегрузки не были частью оригинального дизайна, ни были введены позже. Короче говоря, они вносят двусмысленность и вводят в заблуждение сообщения об ошибках.


Однако вместо перегрузок C++ имеет те же алгоритмы для полных диапазонов в отдельном пространстве имен. std::rangesначиная с C++20. Пример использования заливки:

std::ranges::fill(container, value);

зверство, которое является векторной идиомой "стереть-удалить"

Хотя диапазоны не вводят новые перегрузки функций-членов, существует альтернатива стирания, не являющаяся членами:

std::erase(vector, elem);

Это было исправлено в C++20.

См. Один пример на cppreference

template< ranges::input_range R, class Proj = std::identity,
          std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::range_difference_t<R>
  count_if( R&& r, Pred pred = {}, Proj proj = {} );

bool is_even(int n) {
   return (n % 2 == 0);
}
std::vector<int> l(10);
std::iota(l.begin(), l.end(), 0); // is in numerics which hasn't been rangified.

auto cnt = std::ranges::count_if(arr, is_even);

Другие вопросы по тегам