Related
I was writing functions and came across this situation:
void doSomeThing(std::vector<someType> vec)
{
for(element : vec)
{
// do Something different if it is in vector
}
}
void doSomeThing(someType element)
{
// do Something else if it was not a vector
}
I need them to be separate like above stated. I was wondering if there was a way using templates to deduce the type and do the processing accordingly?
Well, yes, it is possible.
For example, you could do;
template<class someType>
void doSomeThing( const someType &obj )
{
// do something assuming someType is not a vector of something
}
template<class someType>
void doSomeThing( const std::vector<someType> &obj )
{
// do something different if a vector<someType> is passed
}
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
doSomeThing(x); // will call a specialisation of the first form above
doSomething(a); // will call a specialisation of the second form above
}
Personally, I'd do it slightly differently though - instead of overloading for a vector, I'd overload for a pair of iterators. For example, assuming doSomething() is just function that prints to std::cout
template<class someType>
void doSomeThing( const someType &obj )
{
std::cout << obj;
}
template<class Iter>
void doSomeThing( Iter begin, Iter end)
{
while(begin != end)
{
std::cout << *begin << ' ';
++begin;
}
std::cout << '\n';
}
which will work with iterators from any standard container (e.g. specialisations of std::vector, std::list) or anything else that can provide a pair of valid iterators.
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
std::list<double> b {42.0, 45.0};
doSomeThing(x);
doSomething(std::begin(a), std::end(a));
doSomething(std::begin(b), std::end(b));
}
With just little changes you can do so
#include <iostream>
#include <vector>
template <typename T>
void doSomeThing(std::vector<T> vec)
{
for (element : vec)
{
// do Something different if it is in vector
}
}
template <typename T>
void doSomeThing(T element)
{
// do Something else if it was not a vector
}
For example you can write
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
Here is a demonstration program.
#include <iostream>
#include <vector>
#include <type_traits>
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( vec )>, std::vector<T>>
<< '\n';
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( obj )>, std::vector<T>>
<< '\n';
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( v );
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( a );
}
The program output is
true
0 1 2 3 4 5 6 7 8 9
false
0 1 2 3 4 5 6 7 8 9
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 create a generic stringify function for a generic container also for nested container e.g. map<string,vector<list<int>>>?
This is my attempt but it doesn't work.
template<class T>
string stringify(const T& c) {
int length = c.size();
string str = "[";
int i=0;
for (; i <= length-2; i++) {
str += stringfy(c[i]) + ", ";
}
str += c[i] + "]";
return str;
}
It is doable but mostly pointless as you would typically know what kind of data you have to process.
I managed to come up with something like this. It will work for every type that is iterable with for-each loop or a tuple, or has overloaded operator<<. You can do it without C++20 features but it will be a total SFINAE mess.
#include <iostream>
#include <string>
#include <type_traits>
#include <map>
#include <list>
#include <vector>
#include <tuple>
#include <sstream>
using namespace std;
template <typename T>
concept InterableRange = requires (T a) {
std::begin(a);
std::end(a);
};
template <typename T>
concept TupleLikeType = requires (T a) {
std::tuple_size<T>();
};
template<TupleLikeType T>
string stringify(const T& c);
template<class T>
string stringify(const T& c);
template<InterableRange T>
string stringify(const T& c) {
string str = "[ ";
auto size = std::size(c);
std::size_t i = 0;
for (const auto& elem : c) {
str += stringify(elem);
if(i++ < size - 1)
str += ", ";
}
str += " ]";
return str;
}
template<TupleLikeType T>
string stringify(const T& c) {
string str = "[ ";
auto size = std::tuple_size<T>();
std::size_t i = 0;
std::stringstream input;
auto insert = [&input, size, &i](const auto& data) {
input << stringify(data);
if(i++ < size - 1)
{
input.put(',');
input.put(' ');
}
};
std::apply([&insert](const auto&... args){
(insert(args), ...);
}, c);
str += input.str();
str += " ]";
return str;
}
template<class T>
string stringify(const T& c) {
std::stringstream input;
input << c;
return input.str();
}
int main() {
map<string,vector<list<int>>> m {
{ "1", {{1,2}, {3, 4}}},
{ "2", {{10,20}, {30, 40}}}
};
cout << stringify(m);
}
It will print
[ [ [ 1 ], [ [ 1, 2 ], [ 3, 4 ] ] ], [ [ 2 ], [ [ 10, 20 ], [ 30, 40 ] ] ] ]
I did a C++17 solution, the SFINAE is still bearable:
#include <iostream>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <sstream>
// Forward declarations so we can have arbitrary interactions
template<class Container, class Iter = decltype(cbegin(std::declval<Container>()))> // SFINAE to get only containers
std::string stringify(const Container&c);
template<class T1, class T2>
std::string stringify(const std::pair<T1, T2> &p); // Can we get this into the tuple case?
template<class ...Ts>
std::string stringify(std::tuple<Ts...> &t);
template<class T, class = decltype(std::declval<std::stringstream>() << std::declval<T>())>
std::string stringify(T t) {
std::stringstream s;
s << t;
return s.str();
}
template<class ...Ts>
std::string stringify(std::tuple<Ts...> &t) {
const auto string_comma = [] (const auto & arg) { return stringify(arg) + ", "; };
// This prints a , too much but I am too lazy to fix that
return '(' + std::apply([&] (const auto& ...args) { return (string_comma(args) + ...); }, t) + ')';
}
template<class T1, class T2>
std::string stringify(const std::pair<T1, T2> &p) {
return '(' + stringify(p.first) + ", " + stringify(p.second) + ')';
}
template<class Iter>
std::string stringify(Iter begin, Iter end) {
std::string ret{'['};
for(; begin != end;) {
ret += stringify(*begin);
if(++begin != end) {
ret += ", ";
}
}
ret+=']';
return ret;
}
template<class Container, class Iter>
std::string stringify(const Container&c) {
return stringify(cbegin(c), cend(c));
}
int main () {
std::set<std::vector<std::map<int, char>>> v {{{{1, 'A'}, {2, 'E'}}, {{2, 'B'}}}, {{{2, 'C'}}, {{3, 'D'}}}};
std::tuple tup {1.0, "HELLO WORLD", std::pair{67, 42}};
std::cout << stringify(begin(v), end(v)) << '\n';
std::cout << stringify(tup) << '\n';
}
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.
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.