C++11 Reverse Range-Based For-Loop

C++11 reverse range-based for-loop

Actually Boost does have such adaptor: boost::adaptors::reverse.

#include <list>
#include <iostream>
#include <boost/range/adaptor/reversed.hpp>

int main()
{
std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };
for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';
for (auto i : x)
std::cout << i << '\n';
}

Can C++11 and C++17 Range-Based For Loop iterate to a specific position instead of full range of the map?

You either need an external counter to make early exit, eg:

int n = 0;
for(auto [k, v] : map)
{
if(++n > 10) break;
std::cout << k << ": " << v << std::endl;
}

Or, if you are not afraid of copying the map, you can do:

std::map<...> copy { map.begin(), std::next(map.begin(), 10) };

for(auto [k, v] : copy) std::cout << k << ": " << v << std::endl;

Finally, if you can use C++20, then you can simply do this:

#include <ranges>
for(auto [k, v] : map | std::views::take(10))
{
std::cout << k << ": " << v << std::endl;
}

It there an inverse range-based for in C++11?

You can just use Boost.Range's reversed adaptor:

for(int value : ( vec | boost::adaptors::reversed ))
{...}

But standard C++11 doesn't have a similar feature.

I want to reverse the values of map and print it using range based for loop.

As Some Programmer Dude pointed out, but for the completeness of my answer, a std::map is sorted on the key, no matter what order you insert the elements. One option would be to create a new map with the opposite sorting, but that doesn't seem to be what you really want.

It seems you know how about reverse iterators, but not how to get at them when using range-based for. Since it operates on a range, i.e. some type that provides begin and end iterators, you need to create some wrapper around your map that provides this.

Here's a general one I just put together than works in C++11. It won't cover every possible case, and can be made a bit neater in C++14, but it will work for you.

#include <iostream>
#include <iterator>

// The wrapper type that does reversal
template <typename Range>
class Reverser {
Range& r_;
public:
using iterator_type = std::reverse_iterator<decltype(std::begin(r_))>;

Reverser(Range& r) : r_(r) {}

iterator_type begin() { return iterator_type(std::end(r_)); }
iterator_type end() { return iterator_type(std::begin(r_)); }
};

// Helper creation function
template <typename Range>
Reverser<Range> reverse(Range& r)
{
return Reverser<Range>(r);
}

int main()
{
int vals[] = {1, 2, 3, 4, 5};
for (auto i : reverse(vals))
std::cout << i << '\n';
}

This outputs:

$ ./reverse
5
4
3
2
1

(You may also find libraries that provide a similar adapter; Eric Niebler is working on a ranges library for The Standard.)


Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).

What is member interpretation in Range-based for loop (since C++11)?

The "member interpretation" refers to begin_expr and end_expr using members of the iterated type in contrast to using plain offsets for arrays or begin and end free functions.

The array interpretation is off the table, because it is only used for arrays. Next consider that there is std::begin and std::end:

Custom overloads of begin may be provided for classes and enumerations that do not expose a suitable begin() member function, yet can be iterated.

Now consider this example:

#include <iostream>
#include <vector>

class meow {
enum { begin = 1, end = 2};
public:
std::vector<int> data;
};

// non-const iterators
auto begin(meow& m){ return m.data.begin(); }
auto end(meow& m) { return m.data.end(); }
// const iterators
auto begin(const meow& m){ return m.data.begin(); }
auto end(const meow& m) { return m.data.end(); }

int main() {
meow m;
for (const auto& e : m) {}
}

We want to iterate the meows data. But it does not work. The member interpratation is choosen, even though meow::begin and mewo::end are private and the begin and end functions could be used. Hence the error:

<source>: In function 'int main()':
<source>:17:26: error: 'meow::<unnamed enum> begin' is private within this context
for (const auto& e : m) {}
^
<source>:5:12: note: declared private here
enum { begin = 1, end = 2};
^~~~~
<source>:17:26: error: 'begin' cannot be used as a function
for (const auto& e : m) {}
^
<source>:17:26: error: 'meow::<unnamed enum> end' is private within this context
<source>:5:23: note: declared private here
enum { begin = 1, end = 2};
^~~
<source>:17:26: error: 'end' cannot be used as a function
for (const auto& e : m) {}
^

The example works fine when we remove the private enum:

#include <iostream>
#include <vector>

class meow {
//enum { begin = 1, end = 2};
public:
std::vector<int> data;
};

// non-const iterators
auto begin(meow& m){ return m.data.begin(); }
auto end(meow& m) { return m.data.end(); }
// const iterators
auto begin(const meow& m){ return m.data.begin(); }
auto end(const meow& m) { return m.data.end(); }

int main() {
meow m;
for (const auto& e : m) {}
}

Live Demo

What is the meaning of range-based for loop is a C++11 extension and what is expected expression?

warning: range-based for loop is a C++11 extension [-Wc++11-extensions]

What this means is that you are compiling your code with a version of C++ selected that is prior to C++11, but as an extension, your compiler is going to allow you to do it anyway. However, the code is not portable because not all compilers will allow it. That is why it is warning you.

If you want your code to be portable, you should either stop using the range-based-for, or compile with the C++11 version (or greater) of the C++ Standard selected.

This may mean adding a flag like -std=c++11 to your compile command, but it varies by compiler and development environment.

I would also advise configuring your compiler to adhere to strict standards if you want portable code. For example, with GCC or clang this can be done by adding -pedantic-errors to the compile command.



Related Topics



Leave a reply



Submit