Is there anything approximating Haskell's all or any functions as part of the STL? If not, is the below a good implementation (I noticed the sgi STL performed partial specialization if the iterators were random access, though I have not bothered with this)?
template <typename InputIterator, typename Predicate>
inline bool all(InputIterator first, InputIterator last, Predicate pred) {
while (first != last) {
if (!pred(*first)) {
return false;
}
++first;
}
return true;
}
Similarly, how would this best be transformed to iterate two sequences, and return true where a BinaryPredicate returns true for all, and false otherwise? I know this is relatively trivial, but it seems like this should be provided by algorithm, and I want to make sure I'm not overlooking something.
There are not all or any algorithms in C++ currently, but C++0x adds std::all_of and std::any_of algorithms to the C++ standard library. Your implementation may support these already.
Since both of these algorithms need to test every element in the range (at least until they find a match or mismatch), there isn't any reason to specialize them for different types of iterators: the performance when used with forward iterators should be the same as the performance when used with random access iterators.
Your implementation of all is fine; the Visual C++ all_of implementation is effectively the same, except that it uses a for loop instead of a while loop.
how would this best be transformed to iterate two sequences, and return true where a BinaryPredicate returns true for all, and false otherwise?
This is what std::equal does. You'll need to check the sizes of the ranges first to ensure that they are of the same size.
This looks almost equivalent to std::find_if with the predicate inverted to me.
You can use std::find_if like, which returns Iterator last if the predicate returns false for all elements, otherwise it returns the element that it returns true for.
Iterator it = std::find_if (container.begin (), container.end (), predicate);
if (it != container.end ())
// One of them doesn't match
How about foreach from BOOST ? it's not STL but available for any platform.
Related
This program:
#include <ranges>
#include <numeric>
#include <iostream>
int main() {
auto rng = std::ranges::istream_view<int>(std::cin);
std::cout << std::accumulate(std::ranges::begin(rng), std::ranges::end(rng), 0);
}
is supposed to sum up all integers appearing as text on the standard input stream. But - it doesn't compile. I know std::ranges::begin() and std::ranges::end() exist, so what's going on? The compiler tells me it can't find a suitable candidate; why?
From inception up through C++17, everything in <algorithm> is based on iterator pairs: you have one iterator referring to the beginning of a range and one iterator referring to the end of the range, always having the same type.
In C++20, this was generalized. A range is now denoted by an iterator and a sentinel for that iterator - where the sentinel itself need not actually be an iterator of any kind, it just needs to be a type that can compare equal to its corresponding iterator (this is the sentinel_for concept).
C++17 ranges tend to be† valid C++20 ranges, but not necessarily in the opposite direction. One reason is the ability to have a distinct sentinel type, but there are others, which also play into this question (see below).
To go along with the new model, C++20 added a large amount of algorithms into the std::ranges namespace that take an iterator and a sentinel, rather than two iterators. So for instance, while we've always had:
template<class InputIterator, class T>
constexpr InputIterator find(InputIterator first, InputIterator last,
const T& value);
we now also have:
namespace ranges {
template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
constexpr I find(I first, S last, const T& value, Proj proj = {});
template<input_range R, class T, class Proj = identity>
requires indirect_binary_predicate<ranges::equal_to,
projected<iterator_t<R>, Proj>, const T*>
constexpr borrowed_iterator_t<R>
find(R&& r, const T& value, Proj proj = {});
}
The first overload here takes an iterator/sentinel pair and the second takes a range instead.
While a lot of algorithms added corresponding overloads into std::ranges, the ones in <numeric> were left out. There is a std::accumulate but there is no std::ranges::accumulate. As such, the only version we have available at the moment is one that takes an iterator-pair. Otherwise, you could just write:
auto rng = std::ranges::istream_view<int>(std::cin);
std::cout << std::ranges::accumulate(rng, 0);
Unfortunately, std::ranges::istream_view is one of the new, C++20 ranges whose sentinel type differs from its iterator type, so you cannot pass rng.begin() and rng.end() into std::accumulate either.
This leaves you with two options generally (three, if you include waiting for C++23, which will hopefully have a std::ranges::fold):
Write your own range-based and iterator-sentinel-based algorithms. Which for fold is very easy to do.
Or
There is a utility to wrap a C++20 range into a C++17-compatible one: views::common. So you could this:
auto rng = std::ranges::istream_view<int>(ints) | std::views::common;
std::cout << std::accumulate(rng.begin(), rng.end(), 0);
Except not in this specific case.
istream_view's iterators aren't copyable, and in C++17 all iterators must be. So there isn't really a way to provide C++17-compatible iterators based on istream_view. You need proper C++20-range support. The future std::ranges::fold will support move-only views and move-only iterators, but std::accumulate never can.
Which in this case, just leaves option 1.
†A C++20 iterator needs to be default-constructible, which was not a requirement of C++17 iterators. So a C++17 range with non-default-constructible iterators would not be a valid C++20 range.
The problem is that the end of a C++ range is not, in the general case, an iterator, but rather, a sentinel. A sentinel can have a different type than an iterator and admit fewer operations - as, generally speaking, you mostly need to compare against it to know you've reached the end of the range, and may not be allowed to just work with it like any iterator. For more about this distinction, read:
What's the difference between a sentinel and an end iterator?
Now, standard-library algorithms (including the ones in <numeric>) take pairs of iterators of the same type. In your example:
template< class InputIt, class T >
constexpr T accumulate( InputIt first, InputIt last, T init );
see? InputIt must be the type of both the beginning and end of the range. This can (probably) not even be "fixed" for the istream_view range, because the end of the standard input really isn't an iterator per se. (Although maybe you could bludgeon it into being an iterator and throw exceptions when doing irrelevant things with it.)
So, we would need either a new variant of std::accumulate or an std::ranges::accumulate, which we currently don't have. Or, of course, you could write that yourself, which should not be too difficult.
Edit: One last option, suggested by #RemyLebeau, is to use an std::istream_iterator instead:
std::cout << std::accumulate(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
0);
Consider I had an std::vector such that its contents were std::strings and {"a","b","c"}. If I were to perform std::find() looking for "a", would it stop once it iterated over "a" (ie. short-circuit) or continue to the end?
std::vector<std::string> vec;
vec.insert(vec.begin(), "a");
vec.insert(vec.begin(), "b");
vec.insert(vec.begin(), "c");
Which is faster?
std::find(vec.begin(), vec.end(), "a");
std::find(vec.begin(), vec.end(), "c");
See the possible implimenation of std::find
template<class InputIt, class T>
constexpr InputIt find(InputIt first, InputIt last, const T& value)
{
for (; first != last; ++first) {
if (*first == value) { // if the condition met
return first; // ---> here returns the iterator
}
}
return last;
}
It will stop iterating, once it finds the match.
Based on description here, yes it does.
Returns the first element in the range [first, last) that satisfies
specific criteria.
Complexity: At most last - first applications of the predicate
And by taking a look at its possible implementations it is stated that std::find uses short circuit
The C++17 standard draft defines the behavior of std::find in [alg.find] (only part relevant to overload used in question cited):
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last,
const T& value);
[...]
Returns: The first iterator i in the range [first, last) for which the following corresponding conditions hold: *i == value, [...]. Returns last if no such iterator is found.
Complexity: At most last - first applications of the corresponding predicate.
Previous standard versions, including C++03, contain basically the same wording.
Nothing in this guarantees that the elements are searched in any specific order at all or that std::find must stop testing the predicate once it found a match.
However, since the function must return the first iterator in the range satisfying the condition, it makes no sense to test out-of-order, because if a match was found, all previous iterators would need to be tested for an earlier match anyway.
Once a match is found it is also pointless to continue applying the predicate and the standard only requires the predicate to be applied "at most" as often as there are elements in the range.
Therefore any reasonable sequential implementation of std::find will search the iterator range in-order and return when a match is found. If an implementation did not do that, users would complain about it as soon as they noticed. Standard library implementors want their code to be fast where possible and they have no benefit letting their code do more work than necessary.
I suppose though that an implementation could make use of parallelization if it knows that this will not cause data races for the given types and in that case it might happen that the search examines iterators beyond the first match. Whether something like this is implemented in any standard library for the non-parallel std::find overload from the question, I don't know.
(This question has the same "question template" as Why does std::max_element require a ForwardIterator? but the answer has to be different, because std::fill doesn't return an iterator into the output sequence.)
std::fill is defined to work only when the output range is given by a pair of ForwardIterators. However, the superficially similar std::fill_n works fine with OutputIterator.
Surely the algorithm is simply
template<class OutIt, class T>
void fill(OutIt first, OutIt last, T value)
{
while (first != last) {
*first = value;
++first;
}
}
What about this algorithm requires ForwardIterator? What am I missing?
Output iterators are not comparable. The == and != operators are not defined for output iterators.
You need a forward iterator, because it
satisfies the requirements of an input iterator
which supports EqualityComparable.
With output iterators, std::fill cannot compare first with last:
while (first != last) {
Not supported, for output iterators.
std::fill_n avoids this comparison, it just uses the counter to write to the iterator, so all it needs is an output iterator.
There is no notion of "range" for OutputIterator. Thus you must provide a repetition count. With ForwardIterator you can work over a range of elements.
Those are semantically different things. fill_n is for adding some elements starting from a supplied iterator. fill is for changing a range of elements.
Take inserters (e.g. a back_inserter) for an example. You can insert more elements than there is in the container, so last doesn't even make sense.
OutputIterator gives you a place where you can throw in an object. ForwardIterator objects must exists.
From cppreference:
The only valid use of operator* with an output iterator is on the left of an assignment: operator* may return a proxy object, which defines a member operator= (which may be a template)
This means you basically cannot read from it, which is in the contrast to the ForwardIterator:
A ForwardIterator is an Iterator that can read data from the pointed-to element.
The C++11 algorithms std::is_sorted and std::is_sorted_until both require ForwardIterators. However, the Boost.Range version boost::is_sorted only requires SinglePassRanges which corresponds to InputIterators. In particular, it delegates to an an iterator-based implementation like this:
template<class Iterator, class Comp>
inline Iterator is_sorted_until (Iterator first, Iterator last, Comp c) {
if (first == last)
return last;
Iterator it = first; ++it;
for (; it != last; first = it, ++it)
if (c(*it, *first))
return it;
return it;
}
Here we see a *first iterator dereference that happens after the ++it iterator increment. This means that Iterator should have ForwardIterator as its required category. Why? Because the Standard says so in
24.2.3 Input iterators [input.iterators]/p2 (see table 107 with the line about ++r)
post: any copies of the previous value of r are no longer required
either to be dereferenceable or to be in the domain of ==.
Note: this is not intended to be "a proof by single example", but it seems that any comparison based algorithm (e.g. adjacent_find) would necessarily require forward iterators in order to be able to make a comparison between two iterators.
Question: why doesn't the Boost.Range version of is_sorted require the stronger concept of ForwardRange (and ForwardIterator for its low-level routines) that is required by std::is_sorted? Is it a bug in Boost.Range?
It looks like the iterator versions in boost.algorithm correctly require ForwardIterators. And believe it or not, there are also range-based versions in boost.algorithm. Code duplication at its best. The documentation is lagging behind the source according to Ticket #9367, Changeset #86741 corrects the rest of the documentation to state that all flavors of the sort-checking algorithms require ForwardIterators.
I would prefer the implementations in <boost/algorithm/cxx11/is_sorted.hpp> over those in <boost/range/algorithm_ext/is_sorted.hpp> which seem to be bit-rotting since 2010.
EDIT: Digging around, it appears that the Boost.Range implementations did require ForwardIterator, but this commit broke them in 2010?!?.
I have an iterator. Say I need to traverse the set not from the beginning but from some particular point. Also it is quite difficult for me to get the values stored in the sets as they are pointers. So how to i modify my code to traverse through my sets from a point that is not the begining. ?
Here is the code:
for(iter=make.at(level).begin();iter!=make.at(level).end();iter++)
{
Function(*iter);
}
Using this gives an error:
for(iter=make.at(level).begin()+10;iter!=make.at(level).end();iter++)
{
Function(*iter);
}
There are different types of iterators: ForwardIterator, BidirectionalIterator, and RandomAccessIterator.
ForwardIterator allows you to move forward only, using the increment operator. BidirectionalIterator allows both directions. RandomAccessIterator allows any advancement, including operator+ and operator-.
The one you're thinking in terms of is RandomAccessIterator, like the one found in std::vector. What std::set uses, though, is the BidirectionalIterator. That means you can only increment and decrement.
Therefore, you need to make your iterator outside of your loop and advance it forward ten times. To make it simple, std::advance does this, and has different compatibility for BidirectionalIterator, as well as ForwardIterator (linear time because of only one increment at a time), and RandomAccessIterator (constant time due to operator+).
std::set<T>::iterator iter = make.at(level).begin(); //more C++03 way
auto iter = std::begin (make.at(level)); //more C++11 way
std::advance (iter, 10); //start iterator 10 elements past beginning
for (...)