19

Stand-alone STL algorithms (like std::count_if) take pair of iterators. In all cases where I use those (and in all examples I've seen online!), I find myself typing

std::count_if(myContainer.begin(),myContainer.end(), /* ... */ );

Is there a reason why shorthand templates of the style

std::count_if(myContainer, /* ... */ );

are not provided, given that more of than not is the operaation performed on the whole container? Did I just overlook it? Is the answer different for c++11 and c++03?

iammilind
  • 68,093
  • 33
  • 169
  • 336
eudoxos
  • 18,545
  • 10
  • 61
  • 110
  • 2
    It is a simply a design decision. Many people don't find it such a good choice (see http://www.slideshare.net/rawwell/iteratorsmustgo). Boost provides those algorithms using their Range concepts. – visitor Nov 17 '11 at 09:32
  • 1
    In C++20, problem's solved (https://en.cppreference.com/w/cpp/ranges) – PiotrNycz Nov 29 '21 at 14:56

4 Answers4

10

There is a nice blog-post by Herb Sutter discussing the question. The gist is that adding container-based overloads for algorithms can create ambiguities if an overload for that algorithm with the same number of template-parameters already exists. Concepts were intended to fix that problem.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
3

STL principle and flexibility is mainly because of operating on iterators instead of containers. It is not a big problem, you can re-use trick I am using from my early C years:

#define FULL_RANGE(c) (c).begin(), (c).end()

std::copy(FULL_RANGE(c), std::ostream_iterator<c::value_type>(cout, "\n")); 
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • That's a clever trick actually, though I'd probably call it ALL and nowadays use std::begin and std::end – André Feb 16 '15 at 15:12
2

One reason could be to provide the flexibility for iterator range. You may not need to iterate through all elements sometime:

<iterator> it = myContainer.begin();
it++; // do something
it++; // do something
...
std::count_if(it, myContainer.end(), /* ... */ );

Also, you can always have a wrapper which does this for you:

template<typename T>
... count_if (T myContainer, ...)
{
  std::count_if(myContainer.begin(), myContainer.end(), /* ... */ );
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 2
    In C++11, use `begin(myContainer)` and `end(myContainer)` in order to make it work with arrays as well. – Sjoerd Nov 17 '11 at 09:34
  • 3
    The 0.1%-case where you need to iterate only over a part of the container justify typing `.begin()` and `.end()` in the 99.9% cases, if it is possible to have both. – eudoxos Nov 17 '11 at 10:09
  • 2
    @Euxodos: Yes, those 0.1% of cases would be trivially solved with `count_if(make_range(it, myContainer.end()), /*...*/);`. - Historically it seems that algorithms were added to the standard library in a hurry, and iterators were such a novel idea at a time. Had they had a bit more experience with them, things could have turned out different. But now it seems, they can't let go of the old things, and can't add new things, unless it can be done cleanly. – UncleBens Nov 17 '11 at 16:12
-1

Simply because STL algorithms are connected / talks with container using iterators.

Avinash
  • 12,851
  • 32
  • 116
  • 186