Square and round brackets operator, how to choose overloads? - c++

I want to access to some class data using operator[] but depending on the index type into the square brackets return one kind of data or other. As a simplified example:
struct S
{
int &operator []( int index ) { std::cout << "[i]"; return i_buffer[index]; }
short &operator [](short index) { std::cout << "[s]"; return s_buffer[index]; }
private:
int i_buffer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
There's no way to write a short literal, so the only way to choose the short overload is by casting:
S s;
std::cout << s[9] << '\n'; // prints [i]9
std::cout << s[(short)9] << '\n'; // prints [s]999
But I don't like it and I was wondering if there's different options.
What I've tried?
Tagged parameter.
First I've tried to use "tags":
struct S
{
enum class i_type : std::int32_t {};
enum class s_type : std::int32_t {};
int &operator [](i_type index)
{ std::cout << "[i]"; return i_buffer[static_cast<int>(index)]; }
short &operator [](s_type index)
{ std::cout << "[s]"; return s_buffer[static_cast<int>(index)]; }
private:
int i_buffer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
That works but is still a little verbose:
S s;
std::cout << s[9] << '\n'; // error, no possible overload to be taken
std::cout << s[S::i_type{9}] << '\n'; // prints [i]9
std::cout << s[S::s_type{9}] << '\n'; // prints [s]999
Template.
As a crazy workaround I wanted to try to template the operator:
struct S
{
template <typename T>
T &operator [](T) { std::cout << "???"; return 0; }
private:
int i_buffer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
template <>
int &S::operator [](int index) { std::cout << "[i]"; return i_buffer[index]; }
template <>
short &S::operator [](short index) { std::cout << "[s]"; return s_buffer[index]; }
The template version behaves as the original code, but there's no easy way to specify a type parameter along with the operator[]:
S s;
std::cout << s[9] << '\n'; // prints [i]9 like before
std::cout << s[(short)9] << '\n'; // prints [s]999 like before
std::cout << s<short>[9] << '\n'; // s is not template
std::cout << s[9]<short> << '\n'; // nonsense
// Correct but utterly verbose and hard to write and read
std::cout << s.operator[]<short>(9) << '\n';
Question.
All the issues described also happens with operator(), I want to know if there's more alternatives that I'm not aware of?

I think that using a named method is a much better idea than using operator[] in your situation, as it would be easier to understand that two separate buffers are being accessed by reading the source code.
Regardless, if you want to use your operator[] approach, you could use strong typedefs and user defined literals to have type-safety with minimal syntactic overhead:
BOOST_STRONG_TYPEDEF(std::size_t, int_index)
BOOST_STRONG_TYPEDEF(std::size_t, short_index)
struct S
{
auto& operator[](int_index i) { /* ... */ }
auto& operator[](short_index i) { /* ... */ }
};
auto operator "" _ii(unsigned long long int x) { return int_index{x}; }
auto operator "" _si(unsigned long long int x) { return short_index{x}; }
You can then call your methods as follows:
S s;
auto& some_int = s[15_ii];
auto& some_short = s[4_si];
wandbox example

I think I'd use std::tie from the <tuple> library and then write a little helper to find the correct reference type:
#include <tuple>
#include <iostream>
template<class As, class...Ts>
auto& as(std::tuple<const Ts&...>ts)
{
return std::get<As const&>(ts);
};
template<class As, class...Ts>
auto& as(std::tuple<Ts&...>ts)
{
return std::get<As &>(ts);
};
struct S
{
// both cost and mutable version provided for completeness.
auto operator[](std::size_t i) const {
return std::tie(i_buffer[i], s_buffer[i]);
}
auto operator[](std::size_t i) {
return std::tie(i_buffer[i], s_buffer[i]);
}
private:
int i_buffer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
int main()
{
auto s = S();
const auto x = S();
std::cout << "short is : " << as<short>(s[5])<< '\n';
std::cout << "int is : " << as<int>(s[5])<< '\n';
std::cout << "short is : " << as<short>(x[6])<< '\n';
std::cout << "int is : " << as<int>(x[6])<< '\n';
}
This way, the code is explicit but still succinct.
expected output:
short is : 555
int is : 5
short is : 666
int is : 6
Having read the further comments, I might choose to store the matrix in (say) row-wise form and then provide a col-wise wrapper.
A barely functional example:
#include <tuple>
#include <iostream>
#include <array>
template<std::size_t Rows, std::size_t Cols>
struct RowWiseMatrix
{
auto& operator[](std::size_t i) { return data_[i]; }
std::array<std::array<double, Cols>, Rows> data_;
};
template<std::size_t Rows, std::size_t Cols>
struct ColumnProxy
{
ColumnProxy(std::array<std::array<double, Cols>, Rows>& data, std::size_t col)
: data_(data), col_(col)
{
}
auto& operator[](std::size_t i) { return data_[i][col_]; }
std::array<std::array<double, Cols>, Rows>& data_;
std::size_t col_;
};
template<std::size_t Rows, std::size_t Cols>
struct ColWiseProxy
{
ColWiseProxy(RowWiseMatrix<Rows, Cols>& mat) : underlying_(mat) {}
auto operator[](std::size_t i) { return ColumnProxy<Rows, Cols> { underlying_.data_, i }; }
RowWiseMatrix<Rows, Cols>& underlying_;
};
template<std::size_t Rows, std::size_t Cols>
auto& rowWise(RowWiseMatrix<Rows, Cols>& mat)
{
return mat;
};
template<std::size_t Rows, std::size_t Cols>
auto colWise(RowWiseMatrix<Rows, Cols>& mat)
{
return ColWiseProxy<Rows, Cols>(mat);
};
int main()
{
auto m = RowWiseMatrix<3, 3> {
std::array<double, 3>{ 1, 2, 3 },
std::array<double, 3>{ 4, 5, 6},
std::array<double, 3>{ 7, 8, 9}
};
std::cout << rowWise(m)[0][2] << '\n';
std::cout << colWise(m)[0][2] << '\n';
}
Expected output:
3
7

I agree with Vittorio Romeo that the best solution is a named method.
However here is a solution:
template <class T> struct S_proxy {
T* data;
T& operator[](std::size_t i) { return data[i]; }
};
struct S
{
auto i_type() { return S_proxy<int>{i_buffer}; };
auto s_type() { return S_proxy<short>{s_buffer}; };
private:
int i_buffer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_buffer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
and use:
S s;
return s.s_type()[2];

If i_type and s_type are supposed to have a meaning by themselves, it is possible to add semantics to operators []. Something like
#include <iostream>
struct Month {
explicit Month(int m)
: m(m)
{
}
int m;
};
struct Day {
explicit Day(short d)
: d(d)
{
}
short d;
};
struct S {
int& operator[](const Month& mes)
{
std::cout << "[i]";
return i_bufer[mes.m];
}
short& operator[](const Day& dis)
{
std::cout << "[s]";
return s_bufer[dis.d];
}
private:
int i_bufer[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
short s_bufer[10]{ 0, 111, 222, 333, 444, 555, 666, 777, 888, 999 };
};
int main()
{
S s;
std::cout << s[Month(9)] << '\n'; // muestra [i]9
std::cout << s[Day(9)] << '\n'; // muestra [s]999
}

Related

Is there a way to iterate a vector in reverse using for each loop? [duplicate]

Is there a container adapter that would reverse the direction of iterators so I can iterate over a container in reverse with range-based for-loop?
With explicit iterators I would convert this:
for (auto i = c.begin(); i != c.end(); ++i) { ...
into this:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
I want to convert this:
for (auto& i: c) { ...
to this:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Is there such a thing or do I have to write it myself?
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';
}
Actually, in C++14 it can be done with a very few lines of code.
This is a very similar in idea to #Paul's solution. Due to things missing from C++11, that solution is a bit unnecessarily bloated (plus defining in std smells). Thanks to C++14 we can make it a lot more readable.
The key observation is that range-based for-loops work by relying on begin() and end() in order to acquire the range's iterators. Thanks to ADL, one doesn't even need to define their custom begin() and end() in the std:: namespace.
Here is a very simple-sample solution:
// -------------------------------------------------------------------
// --- Reversed iterable
template <typename T>
struct reversion_wrapper { T& iterable; };
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
This works like a charm, for instance:
template <typename T>
void print_iterable (std::ostream& out, const T& iterable)
{
for (auto&& element: iterable)
out << element << ',';
out << '\n';
}
int main (int, char**)
{
using namespace std;
// on prvalues
print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));
// on const lvalue references
const list<int> ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector<int> ints_vec { 0, 0, 0, 0, };
size_t i = 0;
for (int& el: reverse(ints_vec))
el += i++;
print_iterable(cout, ints_vec);
print_iterable(cout, reverse(ints_vec));
return 0;
}
prints as expected
4,3,2,1,
4,3,2,1,
3,2,1,0,
0,1,2,3,
NOTE std::rbegin(), std::rend(), and std::make_reverse_iterator() are not yet implemented in GCC-4.9. I write these examples according to the standard, but they would not compile in stable g++. Nevertheless, adding temporary stubs for these three functions is very easy. Here is a sample implementation, definitely not complete but works well enough for most cases:
// --------------------------------------------------
template <typename I>
reverse_iterator<I> make_reverse_iterator (I i)
{
return std::reverse_iterator<I> { i };
}
// --------------------------------------------------
template <typename T>
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template <typename T>
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
Got this example from cppreference. It works with:
GCC 10.1+ with flag -std=c++20
#include <ranges>
#include <iostream>
int main()
{
static constexpr auto il = {3, 1, 4, 1, 5, 9};
std::ranges::reverse_view rv {il};
for (int i : rv)
std::cout << i << ' ';
std::cout << '\n';
for(int i : il | std::views::reverse)
std::cout << i << ' ';
}
If you can use range v3 , you can use the reverse range adapter ranges::view::reverse which allows you to view the container in reverse.
A minimal working example:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main()
{
std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto const& e : ranges::view::reverse(intVec)) {
std::cout << e << " ";
}
std::cout << std::endl;
for (auto const& e : intVec) {
std::cout << e << " ";
}
std::cout << std::endl;
}
See DEMO 1.
Note: As per Eric Niebler, this feature will be available in C++20. This can be used with the <experimental/ranges/range> header. Then the for statement will look like this:
for (auto const& e : view::reverse(intVec)) {
std::cout << e << " ";
}
See DEMO 2
This should work in C++11 without boost:
namespace std {
template<class T>
T begin(std::pair<T, T> p)
{
return p.first;
}
template<class T>
T end(std::pair<T, T> p)
{
return p.second;
}
}
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
return std::reverse_iterator<Iterator>(it);
}
template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r)
{
return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));
}
for(auto x: make_reverse_range(r))
{
...
}
Does this work for you:
#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>
int main(int argc, char* argv[]){
typedef std::list<int> Nums;
typedef Nums::iterator NumIt;
typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
typedef boost::iterator_range<NumIt> irange_1;
typedef boost::iterator_range<RevNumIt> irange_2;
Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );
// prints: 1 2 3 4 5 6 7 8
for(auto e : r1)
std::cout << e << ' ';
std::cout << std::endl;
// prints: 8 7 6 5 4 3 2 1
for(auto e : r2)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}
Sorry but with current C++ (apart from C++20) all these solutions do seem to be inferior to just use index-based for. Nothing here is just "a few lines of code". So, yes: iterate via a simple int-loop. That's the best solution.
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
eg:
int main(int argc, const char * argv[]) {
std::vector<int> arr{1, 2, 3, 4, 5};
int arr1[] = {1, 2, 3, 4, 5};
for (auto i : r_wrap(arr)) {
printf("%d ", i);
}
printf("\n");
for (auto i : r_wrap(arr1)) {
printf("%d ", i);
}
printf("\n");
return 0;
}
You could simply use BOOST_REVERSE_FOREACH which iterates backwards. For example, the code
#include <iostream>
#include <boost\foreach.hpp>
int main()
{
int integers[] = { 0, 1, 2, 3, 4 };
BOOST_REVERSE_FOREACH(auto i, integers)
{
std::cout << i << std::endl;
}
return 0;
}
generates the following output:
4
3
2
1
0
If not using C++14, then I find below the simplest solution.
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
T& m_T;
METHOD(begin());
METHOD(end());
METHOD(begin(), const);
METHOD(end(), const);
};
#undef METHOD
template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }
Demo.
It doesn't work for the containers/data-types (like array), which doesn't have begin/rbegin, end/rend functions.

Is there any shortcut method to print 2D-array c++

Is there any shortcut method in c++ to output 2d array(i.e. apart from for loop)?
Is there a special function in STL to output it.
Well, since you mentioned STL functions, you could use the std::for_each function with lambda functions to print the 2D array:
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
int matrix[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
auto elem_printer = [](int num) { std::cout << num << " "; };
auto row_printer = [&elem_printer](int (&row)[3]) {
std::for_each(std::begin(row),std::end(row),elem_printer);
std::cout << std::endl;
};
std::for_each(std::begin(matrix),std::end(matrix),row_printer);
}
However, this is exactly the same as two for loops, but uglier.
I have this template for streams, which hides away some of the ugliness, and you benefit from it being reusable and it handles multiple dimensions. There is no way to get away without doing the loops somewhere, of course:
template <class Stream, size_t depth>
class Pretty
{
Stream& s;
public:
Pretty(Stream& s): s(s) {}
template <size_t d1, typename T>
Stream& operator <<( T const (&v)[d1])const
{
const char* sep = "{";
for (auto& m : v)
{
s << sep << m;
sep = ", ";
}
s << "}";
return s;
}
template <size_t d1, typename T, size_t d2>
std::ostream& operator <<(T const (&v)[d1][d2])const
{
enum {DENT = 4};
std::string dent (DENT,' ');
std::string indent(depth*DENT,' ');
std::string sep = "{\n" + indent + dent;
for (auto& m : v)
{
s << sep; Pretty<Stream,depth+1>(s) << m;
sep = ",\n" + indent + dent;
}
s << "\n" << indent << "}";
return s;
}
};
class PrettyNext
{};
Pretty<std::ostream,0> operator << (std::ostream& s, const PrettyNext&)
{
return Pretty<std::ostream,0>(s);
}
And usage:
int i [][3][2] = { { {1,2}, {3,4}, {5,6} },{{0}}};
std::cout << "This is a test:\n" << PrettyNext() << i << std::endl;
Output is:
This is a test:
{
{
{1, 2},
{3, 4},
{5, 6}
},
{
{0, 0},
{0, 0},
{0, 0}
}
}
I have been fighting to get this to work directly on std::ostream, but there is a collision with the standard char* handling I can't quite resolve.

no matching function for call to ‘begin(int**&)’

I wrote a c++ program as fllow(3.43.cpp):
#include <iostream>
using std::cout;
using std::endl;
void version_1(int **arr) {
for (const int (&p)[4] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << endl;
}
}
int main() {
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
version_1(arr);
return 0;
}
Then I compile it by using: gcc my.cpp -std=c++11, there is an error I can not deal with.
Info:
3.43.cpp:6:30: error: no matching function for call to ‘begin(int**&)’
for (const int (&p)[4] : arr) {
^
3.43.cpp:6:30: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:42:0,
from /usr/include/c++/4.8.2/string:52,
from /usr/include/c++/4.8.2/bits/locale_classes.h:40,
from /usr/include/c++/4.8.2/bits/ios_base.h:41,
from /usr/include/c++/4.8.2/ios:42,
from /usr/include/c++/4.8.2/ostream:38,
from /usr/include/c++/4.8.2/iostream:39,
from 3.43.cpp:1:
/usr/include/c++/4.8.2/initializer_list:89:5: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
begin(initializer_list<_Tp> __ils) noexcept
I search it in google, but not find similar answer.
Since arr is just a pointer, there's no way to deduce how big it is. But, since you are actually passing in a real array, you can just template your function on its dimensions so you take the actual array by reference rather than having it decay to a pointer:
template <size_t X, size_t Y>
void foo(const int (&arr)[X][Y])
{
std::cout << "Dimensions are: " << X << "x" << Y << std::endl;
for (const int (&row)[Y] : arr) {
for (int val : row) {
std::cout << val << ' ';
}
std::cout << std::endl;
}
}
int main() {
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
foo(arr);
}
std::begin() and std::end() won't work for pointers. They only work for arrays. If you want to deduce the size of your array you'll need to pass it as a reference your function:
#include <cstddef>
template <std::size_t A, std::size_t B>
void version_1(int (&arr)[B][A]) {
for (const int (&p)[A] : arr) {
for (int q : p) {
cout << q << " ";
}
cout << '\n';
}
}
Pointers are not the same as arrays. To be able to use range based for, your container must support std::begin and std::end. Standard C arrays can be used, but not pointers.

C++11 reverse range-based for-loop

Is there a container adapter that would reverse the direction of iterators so I can iterate over a container in reverse with range-based for-loop?
With explicit iterators I would convert this:
for (auto i = c.begin(); i != c.end(); ++i) { ...
into this:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
I want to convert this:
for (auto& i: c) { ...
to this:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Is there such a thing or do I have to write it myself?
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';
}
Actually, in C++14 it can be done with a very few lines of code.
This is a very similar in idea to #Paul's solution. Due to things missing from C++11, that solution is a bit unnecessarily bloated (plus defining in std smells). Thanks to C++14 we can make it a lot more readable.
The key observation is that range-based for-loops work by relying on begin() and end() in order to acquire the range's iterators. Thanks to ADL, one doesn't even need to define their custom begin() and end() in the std:: namespace.
Here is a very simple-sample solution:
// -------------------------------------------------------------------
// --- Reversed iterable
template <typename T>
struct reversion_wrapper { T& iterable; };
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
This works like a charm, for instance:
template <typename T>
void print_iterable (std::ostream& out, const T& iterable)
{
for (auto&& element: iterable)
out << element << ',';
out << '\n';
}
int main (int, char**)
{
using namespace std;
// on prvalues
print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));
// on const lvalue references
const list<int> ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector<int> ints_vec { 0, 0, 0, 0, };
size_t i = 0;
for (int& el: reverse(ints_vec))
el += i++;
print_iterable(cout, ints_vec);
print_iterable(cout, reverse(ints_vec));
return 0;
}
prints as expected
4,3,2,1,
4,3,2,1,
3,2,1,0,
0,1,2,3,
NOTE std::rbegin(), std::rend(), and std::make_reverse_iterator() are not yet implemented in GCC-4.9. I write these examples according to the standard, but they would not compile in stable g++. Nevertheless, adding temporary stubs for these three functions is very easy. Here is a sample implementation, definitely not complete but works well enough for most cases:
// --------------------------------------------------
template <typename I>
reverse_iterator<I> make_reverse_iterator (I i)
{
return std::reverse_iterator<I> { i };
}
// --------------------------------------------------
template <typename T>
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template <typename T>
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
Got this example from cppreference. It works with:
GCC 10.1+ with flag -std=c++20
#include <ranges>
#include <iostream>
int main()
{
static constexpr auto il = {3, 1, 4, 1, 5, 9};
std::ranges::reverse_view rv {il};
for (int i : rv)
std::cout << i << ' ';
std::cout << '\n';
for(int i : il | std::views::reverse)
std::cout << i << ' ';
}
If you can use range v3 , you can use the reverse range adapter ranges::view::reverse which allows you to view the container in reverse.
A minimal working example:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main()
{
std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto const& e : ranges::view::reverse(intVec)) {
std::cout << e << " ";
}
std::cout << std::endl;
for (auto const& e : intVec) {
std::cout << e << " ";
}
std::cout << std::endl;
}
See DEMO 1.
Note: As per Eric Niebler, this feature will be available in C++20. This can be used with the <experimental/ranges/range> header. Then the for statement will look like this:
for (auto const& e : view::reverse(intVec)) {
std::cout << e << " ";
}
See DEMO 2
This should work in C++11 without boost:
namespace std {
template<class T>
T begin(std::pair<T, T> p)
{
return p.first;
}
template<class T>
T end(std::pair<T, T> p)
{
return p.second;
}
}
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
return std::reverse_iterator<Iterator>(it);
}
template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r)
{
return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));
}
for(auto x: make_reverse_range(r))
{
...
}
Does this work for you:
#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>
int main(int argc, char* argv[]){
typedef std::list<int> Nums;
typedef Nums::iterator NumIt;
typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
typedef boost::iterator_range<NumIt> irange_1;
typedef boost::iterator_range<RevNumIt> irange_2;
Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );
// prints: 1 2 3 4 5 6 7 8
for(auto e : r1)
std::cout << e << ' ';
std::cout << std::endl;
// prints: 8 7 6 5 4 3 2 1
for(auto e : r2)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}
Sorry but with current C++ (apart from C++20) all these solutions do seem to be inferior to just use index-based for. Nothing here is just "a few lines of code". So, yes: iterate via a simple int-loop. That's the best solution.
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
eg:
int main(int argc, const char * argv[]) {
std::vector<int> arr{1, 2, 3, 4, 5};
int arr1[] = {1, 2, 3, 4, 5};
for (auto i : r_wrap(arr)) {
printf("%d ", i);
}
printf("\n");
for (auto i : r_wrap(arr1)) {
printf("%d ", i);
}
printf("\n");
return 0;
}
You could simply use BOOST_REVERSE_FOREACH which iterates backwards. For example, the code
#include <iostream>
#include <boost\foreach.hpp>
int main()
{
int integers[] = { 0, 1, 2, 3, 4 };
BOOST_REVERSE_FOREACH(auto i, integers)
{
std::cout << i << std::endl;
}
return 0;
}
generates the following output:
4
3
2
1
0
If not using C++14, then I find below the simplest solution.
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
T& m_T;
METHOD(begin());
METHOD(end());
METHOD(begin(), const);
METHOD(end(), const);
};
#undef METHOD
template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }
Demo.
It doesn't work for the containers/data-types (like array), which doesn't have begin/rbegin, end/rend functions.

How to sort with a lambda?

sort(mMyClassVector.begin(), mMyClassVector.end(),
[](const MyClass & a, const MyClass & b)
{
return a.mProperty > b.mProperty;
});
I'd like to use a lambda function to sort custom classes in place of binding an instance method. However, the code above yields the error:
error C2564: 'const char *' : a function-style conversion to a built-in type can only take one argument
It works fine with boost::bind(&MyApp::myMethod, this, _1, _2).
Got it.
sort(mMyClassVector.begin(), mMyClassVector.end(),
[](const MyClass & a, const MyClass & b) -> bool
{
return a.mProperty > b.mProperty;
});
I assumed it'd figure out that the > operator returned a bool (per documentation). But apparently it is not so.
You can use it like this:
#include<array>
#include<functional>
using namespace std;
int main()
{
array<int, 10> arr = { 1,2,3,4,5,6,7,8,9 };
sort(begin(arr),
end(arr),
[](int a, int b) {return a > b; });
for (auto item : arr)
cout << item << " ";
return 0;
}
Can the problem be with the "a.mProperty > b.mProperty" line? I've gotten the following code to work:
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <sstream>
struct Foo
{
Foo() : _i(0) {};
int _i;
friend std::ostream& operator<<(std::ostream& os, const Foo& f)
{
os << f._i;
return os;
};
};
typedef std::vector<Foo> VectorT;
std::string toString(const VectorT& v)
{
std::stringstream ss;
std::copy(v.begin(), v.end(), std::ostream_iterator<Foo>(ss, ", "));
return ss.str();
};
int main()
{
VectorT v(10);
std::for_each(v.begin(), v.end(),
[](Foo& f)
{
f._i = rand() % 100;
});
std::cout << "before sort: " << toString(v) << "\n";
sort(v.begin(), v.end(),
[](const Foo& a, const Foo& b)
{
return a._i > b._i;
});
std::cout << "after sort: " << toString(v) << "\n";
return 1;
};
The output is:
before sort: 83, 86, 77, 15, 93, 35, 86, 92, 49, 21,
after sort: 93, 92, 86, 86, 83, 77, 49, 35, 21, 15,
You can sort an array like this:
#include <bits/stdc++.h>
using namespace std;
int main() {
int q[] = {1, 3, 5, 7, 9, 2, 4, 6, 8 ,10};
sort(q, q + 10, [&](int A, int B) { return A < B; });
for (int i = 0; i < 10; i++)
cout << q[i] << ' ';
return 0;
}
before sort: 1 3 5 7 9 2 4 6 8 10
after sort: 1 2 3 4 5 6 7 8 9 10
I'd always like to use lambda to sort a array of struct in acm contests like this:
struct item {
int a, b;
};
vector<item> q;
sort(q.begin(), q.end(), [&](item t1, item t2) {
return t1.a < t2.a;
});