2

Standard ISO C++ has a rich algorithm library including plenty of syntactic sugar like std::max_element, std::fill, std::count, etc.

I'm having a hard time understanding why ISO saw fit to standardize many such trivial algorithms, yet not overloads of algorithms which operate on whole containers.

I don't really understand why they added such basic things when we're left without whole container versions (surely by far the most common case) or similarly left with the atrocity that is the vector erase-remove idiom:

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

It seems that every project I write in C++, I end up including my own custom header file which includes basic syntactic sugar for things like this.

Of course, any of the trivial whole-container overloads could be included in a custom header. That's also true of the many of the simple algorithms which were standardized.

What I'm trying to understand is why there's a good reason for things in the standard like std::max_element and std::fill on ranges, but not versions that operate on whole containers, or for other syntactic sugar that reduces the verbosity of writing C++ code.

Tumbleweed53
  • 1,491
  • 7
  • 13
  • 2
    I can't say why we didn't have it before, but we have it (mostly) now: https://en.cppreference.com/w/cpp/ranges – NathanOliver Nov 19 '20 at 20:46
  • 2
    What about when you want to run those algorithms on a sub-range of the container? It seems you're basically asking to double the number of functions in the Algorithms section of the library by adding a whole-container version for each one that takes a range. (And quadruple for those that take two ranges) – M.M Nov 19 '20 at 20:46
  • 3
    One could fill an entire book with the rationale for such a design. Alexander Stepanov did just that as a matter of fact (since you tagged this STL). – StoryTeller - Unslander Monica Nov 19 '20 at 20:47
  • Looks like the canonical [target](https://stackoverflow.com/questions/8164738) needs an update. – cigien Nov 19 '20 at 20:49
  • 1
    @cigien More or less a dupe though, no? OK, OP asks about why, but that could be answered in an opinion based manner only here. – πάντα ῥεῖ Nov 19 '20 at 20:51
  • @πάνταῥεῖ Yeah, pretty much. I don't feel like hammering because it's not updated :p The answers aren't particularly exciting either. There's a decent one [here](https://stackoverflow.com/questions/12443621) though. – cigien Nov 19 '20 at 20:53
  • These "trivial" algorithms are often optimized by library vendors to e.g. [use memset when applied to char*](https://github.com/gcc-mirror/gcc/blob/866cd688d1b72b0700a7e001428bdf2fe73fbf64/libstdc%2B%2B-v3/include/bits/stl_algobase.h#L713) – dewaffled Nov 19 '20 at 20:54
  • @cigien That's the right one, with a sufficient answer, yes (even by Dietmar Kühl, a veteran of C++ standards from last century, I remember him being a regular in the c++ lang usenet group :-D ) – πάντα ῥεῖ Nov 19 '20 at 20:59

2 Answers2

4

That has been rectified in C++20

See one example on 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);

Surt
  • 15,501
  • 3
  • 23
  • 39
4

Why hasn't C++ standardized overloads of algorithms which operate on entire containers?

The answer is same as to answer to all questions like this: Such overloads haven't been standardised either because such change hasn't been proposed or such proposal hasn't been accepted. The original STL didn't have such overloads.

An answer to a similar question links to a blog post which has an argument for why such overload would be problematic for some algorithms which may be part of the reason why such overloads weren't part of the original design nor have been introduced later. In short, they would introduce ambiguity and misleading error messages.


Instead of overloads, C++ does however have the same algorithms for full ranges in a separate namespace std::ranges since C++20. An example using fill:

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

atrocity that is the vector erase-remove idiom

Although ranges don't introduce new member function overloads, there is a non-member alternative for erasure:

std::erase(vector, elem);
eerorika
  • 232,697
  • 12
  • 197
  • 326