Reverse iterate over a std::vector with forward iterators - c++

If I have a function which takes a std::vector<T>::const_iterator called begin and a std::vector<T>::const_iterator called end, is it possible for me to iterate over it in a backwards direction?
UPDATE
I can't change the function signature, which is like this:
void func(Foo::const_iterator begin, Foo::const_iterator end)
{
...
}
and called with:
func(foo.begin(), foo.end());
which I also can't change

Yes, you can.
template <typename Foo>
void test(typename Foo::const_iterator begin,
typename Foo::const_iterator end)
{
std::reverse_iterator<typename Foo::const_iterator>
rbegin(end),
rend(begin);
std::copy(rbegin, rend, std::ostream_iterator<typename std::iterator_traits<typename Foo::const_iterator>::value_type>(std::cout));
}
int main()
{
std::vector<int> v{3,1,4,1,5,9,2,6};
test<std::vector<int> >(v.begin(), v.end());
}

I may have misunderstood the question, but do you just need:
while (begin != end) {
--end;
// do something with *end
}
If you need an iterator that goes backwards, ipc's answer gives you one.
In practice with vector you could probably get away with while (begin != end--), but don't be tempted. It's undefined behavior to decrement an iterator in the case where it's at the start of the vector (i.e. when it's equal to the result of vector::begin()).
This code requires at least a BidirectionalIterator. Fortunately, vector has a RandomAccessIterator, which is even better.
If you genuinely only had a ForwardIterator, then you'd have to iterate over the range and store the iterator values somewhere (like a stack), and then use them in reverse order:
std::stack<Foo::const_iterator> iterators;
while (begin != end) {
iterators.push(begin);
++begin;
}
while (!iterators.empty()) {
Foo::const_iterator i = iterators.top();
// do something with *i
iterators.pop();
}
This code requires at least a ForwardIterator (it will not work with a mere InputIterator).

Yes, you can use std::reverse_iterator. It is also a good idea not
to specify the type of the iterator explicitly. Use a template
argument instead.
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename BidirectionalIterator>
void x(BidirectionalIterator b, BidirectionalIterator e) {
std::reverse_iterator<BidirectionalIterator> rb(e), re(b);
std::for_each(rb, re,
[](typename BidirectionalIterator::reference x)
{ std::cout << x << std::endl;});
}
int main()
{
std::vector<int> v{1,2,3,4};
x(begin(v), end(v));
return 0;
}

Related

How to write a generic function to print begin and end iterator elements [duplicate]

This question already has answers here:
How to retrieve value type from iterator in C++?
(4 answers)
Finding the value type of an Iterator
(2 answers)
Closed last year.
The function below, printloop, is able to print the elements in a collection as below. But if I try to remove the loop and use std::copy, how do I get that version, print, to work?
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
// this print function doesn't compile
template <typename iter>
void print(iter begin, iter end) {
std::copy(begin, end,
std::ostream_iterator< what type? >(std::cout, "\t"));
}
template <typename iter>
void printloop(iter begin, iter end) {
while (begin != end) {
std::cout << *begin << '\t';
begin++;
}
}
int main() {
std::vector<int> vec {1,2,3,4,5};
printloop(vec.begin(), vec.end()); // works ok
print(vec.begin(), vec.end()); // how to get working?
}
You might use iterator_traits:
template <typename iter>
void print(iter begin, iter end) {
using value_type = typename std::iterator_traits<iter>::value_type;
std::copy(begin, end, std::ostream_iterator<value_type >(std::cout, "\t"));
}
Demo
std::iterator_traits to the rescue.
Given an iterator type iter, the type being iterated is
typename std::iterator_traits<iter>::value_type
This solution can work even if the iterator doesn't define iter::value_type, such as if the iterator is a raw pointer.

boost::transform_iterator and std::iter_swap

I am trying to generalize a function I have which used to take two iterators to a vector of a specific data-structure, and re-arrange the elements in a certain way using std::iter_swap (like std::sort does).
Since this function only actually needs a subset of the data, and I will need to use it in other contexts in the future, I thought about removing the dependency on the data structure, and use boost::transform_iterator at the point of call to handle the transformation.
Unfortunately, it seems that boost::transform_iterator is not happy with this change. I can imagine why: std::iter_swap is usually implemented as std::swap(*lhs, *rhs), and dereferencing the transform_iterator does not yield the original element to swap in the correct way.
I was wondering if there was a way to handle this case. I am open to use boost::range or the experimental std::ranges ts if it needed.
This question is probably similar to this one, but even there the solution ends up modifying the subset of data the algorithm needs, rather than the outside structure.
Here is an MWE:
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
struct A {
int x;
int y;
};
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
std::iter_swap(begin++, --end);
}
}
template <typename It>
void my_print(It begin, It end) {
for (; begin != end; ++begin)
std::cout << (*begin) << ' ';
std::cout << '\n';
}
int main() {
std::vector<int> x{7,6,5,4,3,2};
my_invert(std::begin(x), std::end(x));
my_print(std::begin(x), std::end(x));
auto unwrap = +[](const A & a) { return a.x; };
std::vector<A> y{{9,8}, {7,6}, {5,4}, {3,2}};
auto begin = boost::make_transform_iterator(std::begin(y), unwrap);
auto end = boost::make_transform_iterator(std::end(y), unwrap);
//my_invert(begin, end); // Does not work.
my_print(begin, end);
return 0;
}
Accessing the underlying iterator
You could access the base() property of transform_iterator (inherited publicly from iterator_adaptor) to implement your custom transform_iter_swap, for swapping the underlying data of the wrapped iterator.
E.g.:
template<class IteratorAdaptor>
void transform_iter_swap(IteratorAdaptor a, IteratorAdaptor b)
{
std::swap(*a.base(), *b.base());
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
transform_iter_swap(begin++, --end);
}
}
After which your example (omitting the std::vector part) runs as expected:
my_invert(begin, end); // OK
my_print(begin, end); // 3 5 7 9
If you want a general function template to cover both the boost (adaptor) iterators as well as typical iterators, you could e.g. use if constexpr (C++17) based on whether the iterators public typedef iterator_category derives from boost::iterators::no_traversal_tag or not:
// expand includes with
#include <boost/iterator/iterator_categories.hpp>
template <class It>
void iter_swap(It a, It b) {
if constexpr(std::is_base_of<
boost::iterators::no_traversal_tag,
typename It::iterator_category>::value) {
std::swap(*a.base(), *b.base());
}
else {
std::swap(*a, *b);
}
}
template <typename It>
void my_invert(It begin, It end) {
while (begin < end) {
iter_swap(begin++, --end);
}
}
The problem comes from the unary predicate you've passed. Notice, that since you allow the return type to be deduced, the return type is deduced to be an int, a copy is returned, and the compilation fails when you try to swap two unmodifiable ints. However, if you were to specify the return type to be int&, like so:
auto unwrap = [](A & a)->int& { return a.x; }; // explicitly demand to return ref
It will compile, and reverse the elements. Tested on gcc 8.1.0 and clang 6.0.0.

C++11: Range-based for loop over range described by templated iterators

In my C++03 code, I have a lot of functions that look like this:
class A {
public:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (Iterator point = begin; point != end; point++) {
mInternal.doSomething(*point);
}
}
private:
DataStructure mInternal;
};
I'm trying to use C++11's features as much as possible in new code, in particular the range-based for loop. My question is, how would I do this with templated iterators? Is there a magic C++ structure that takes two templated iterator types, and turns them into a range expression? In other words, I'm looking for something like this:
class A {
public:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
static_assert(std::is_same<Point, typename std::decay<Iterator>::type>::value, "wrong type mate!"); // extra credit
for (auto&& point : std::magic(begin, end)) {
mInternal.doSomething(point);
}
}
private:
DataStructure mInternal;
};
If there is a new, preferred ways to do this kind of "add a number of objects to this structure" in C++11, I'm all ears, too.
There's nothing in the standard library. Boost has make_iterator_range, a simplified version of which is trivial to write:
template<class Iterator>
struct iter_range {
Iterator begin_, end_;
Iterator begin() const { return begin_; }
Iterator end() const { return end_; }
};
template<class Iterator>
iter_range<Iterator> make_range(Iterator b, Iterator e) { return {b, e}; }
The original question just called push_back. For that, it doesn't need a loop. Just use the C++03 range overload of insert:
mInternal.insert(mInternal.end(), begin, end);
template<class It>
struct range_t {
It b; It e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
return {std::forward<It>(b), std::forward<It>(e)};
}
then:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (auto&& point : range(begin, end)) {
mInternal.doSomething(point);
}
}
and bob is your uncle.
"Range-v3" is a library undergoing the standardization process that contains stuff like this already. Boost also has similar mechanisms.
But this kind of thing is simple enough to roll your own and forget about it. (Better versions include empty, conditionally support size and [], can be constructed from containers and C arrays and anything iterable, know if they are condiguous, conditionally store a copy of the incoming container for reference lifetime extension, etc: but you don't really need any of that).
I would add a function overload and keep the existing function around to make the transition gradual and less disruptive.
template <typename Container>
void doSomethingWithObjects(Container&& c) {
for (auto&& item: c) {
mInternal.doSomething(item);
}
}
You don't actually need to turn them into anything. Just use the iterators with std::for_each:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
std::for_each(begin, end, [this](auto&& point){
mInternal.doSomething(point);
}
// C++11 version
std::for_each(begin, end, [this](decltype(*begin)& point) {
mInternal.doSomething(point);
}
}
or write the simple loop:
template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
for (; begin != end; ++begin) {
mInternal.doSomething(*begin);
}
}

c++ proper syntax for templated function of `std::vector<T>::iterator` [duplicate]

This question already has an answer here:
C++ template won't accept iterators
(1 answer)
Closed 9 years ago.
I'm trying to code a template that takes iterators to any type of vector as its arguments. When I try to compile the following, it gives me a no matching function call error.
#include <vector>
struct A { int x; };
template <class T>
void process (typename std::vector<T>::iterator begin,
typename std::vector<T>::iterator end)
{ for(; begin != end; begin++) { /*do_something*/ } }
int main()
{
std::vector <A> obj;
process(obj.begin(), obj.end());
}
1 the type T cannot be deduced from the argument types.
2 Why would you want to restrict the function to only accept iterators to std::vector elements? If you really only want vector elements, better take std::vector<T> const& as argument. But better simply take any iterator arguments (or any container argument).
edit okay, here is an example. You may omit the static_assert, when this becomes identical (apart from the return type) to std::for_each(begin,end,do_something);
template <class It>
void process(It begin, const It end)
{
static_assert(std::is_same<typename std::iterator_traits<It>::iterator_category,
std::random_access_iterator_tag>::value,
"arguments not random access iterators");
for (; begin != end; ++begin)
do_something(*begin);
}
Per the OP's request, see below. you can use any valid container forward iterator that supports value references from operator *() I.e. a vector, deque, list, etc. This does not employ the static assert logic mentioned by chris, I leave that for you to decide.
#include <iostream>
#include <iterator>
template<typename Iterator>
void process(Iterator start, Iterator stop)
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
for (Iterator it=start; it != stop; ++it)
{
const value_type& val = (*it);
// do something with val
std::cout << val << std::endl;
}
}
int main()
{
int ar[] = { 1,2,3,4,5 };
process(std::begin(ar), std::end(ar));
return 0;
}

overloading of template function error C2688

i can't compile the following code
namespace sequential_sort
{
template<class T>
void sort(std::list<T>& source)
{
sort(source.begin(), source.end()); //(1)
}
template<class Iter>
void sort(Iter begin, Iter end)
{
if(begin == end)
return;
typedef Iter::value_type value_type;
value_type value = *(begin);
Iter part = std::partition(begin, end, [&value](const value_type&->bool{return t < value;});
sort(begin, part);
Iter divide = part;
divide++;
sort(divide, end);
}
}
It says that at line (1) I have error C2688 ambiguous call to overloaded functions.
I can't understand why, overloaded functions even have different number of parameters?
There are a few issues at play:
1) You need to declare your single parameter sequential_sort::sort function before the two parameter one, unless you want to another sort function. You probably don't see the effect of this because you are using a Windows C++ compiler, which is not standards compliant in this respect. What should have happened is that std::sort was unambiguously picked, and that wouldn't compile because it requires random access iterators (std::list has a sort member function which you should use instead of std::sort).
2) Once that is fixed, since you are passing std::list iterators to the two parameter sort, argument dependent lookup (ADL) means std::sort is considered too. This is the cause of the ambiguity. You can fix this by being specific about which two-parameter sort you want to use:
#include <list>
#include <algorithm>
namespace sequential_sort
{
template<class Iter>
void sort(Iter begin, Iter end) { }
template<class T>
void sort(std::list<T>& source)
{
sequential_sort::sort(source.begin(), source.end()); //(1)
//^^^^^^^^^^^^^^^
}
}