C++11 reverse range-based for-loop - c++

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.

Related

Make a common function for a "type" and the vector of "type" using templates in C++

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 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.

Why can't I manually define a template parameter?

I have a simple sample which provides:
a struct template:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
a function template:
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
I can use it to skip items in foreach loop of a (i.e) std::vector:
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
}
This works as intended, however I don't really understand the need of the function template (2).
I tried to write the foreach loop as this:
for (auto p : range_t<std::vector::const_iterator>(v.begin()+1, v.end()))
But for this I always got
error: template argument 1 is invalid
This might be a duplicate question, feel free to mark it as duplicate and please let me know the duplicated question which answers to all of these questions:
Why is the template argument invalid here?
(How) can I skip the function template?
How can I create a function template which would work as this:
myskipper would get only v as parameter in the foreach loop:
template<typename T>
range_t<T::const_iterator> myskipper(T c) {
return range_t<T::const_iterator>(c.begin()+1, c.end());
}
...
for (auto p : myskipper(v)) ...
Based on the comments and this article about iterator overflow, here a complete working example:
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin() { return b; }
T end() { return e; }
};
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
template<typename T>
range_t<typename T::iterator> skip(T &c, typename T::size_type skipCount)
{
return range_t<typename T::iterator>(c.begin() + std::min(c.size(), skipCount), c.end());
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : range_t(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
std::cout << std::endl;
for (auto p : skip(v, 3))
{
std::cout << p << " ";
}
std::cout << std::endl;
}

Sort just one member of the classes in a vector, leaving the other members unchanged

There are tons of answers for sorting a vector of struct in regards to a member variable. That is easy with std::sort and a predicate function, comparing the structs member. Really easy.
But I have a different question. Assume that I have the following struct:
struct Test {
int a{};
int b{};
int toSort{};
};
and a vector of that struct, like for example:
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
I do not want to sort the vectors elements, but only the values in the member variable. So the expected output should be equal to:
std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };
I wanted to have the solution to be somehow a generic solution. Then I came up with a (sorry for that) preprocessor-macro-solution. Please see the following example code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) \
do { \
std::vector<decltype(Struct::Member)> vt{}; \
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); \
std::sort(vt.begin(), vt.end()); \
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); \
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "\n\nSorted\n";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
Since macros shouldn't be used in C++, here my questions:
1. Is a solution with the algorithm library possible?
2. Or can this be achieved via templates?
To translate your current solution to a template solution is fairly straight forward.
template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}
And we can call it by passing in the vector and a pointer-to-member.
SpecialSort(tv, &Test::toSort);
Somewhow like this (You just need to duplicate, rename and edit the "switchToShort" funtion for the rest of the variables if you want):
#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
With range-v3 (and soon ranges in C++20), you might simply do:
auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());
Demo

How can I skip the first iteration of range-based for loops?

I would like to do something like this:
for (int p : colourPos[i+1])
How do I skip the first iteration of my colourPos vector?
Can I use .begin() and .end()?
Since C++20 you can use the range adaptor std::views::drop from the Ranges library together with a range-based for loop for skipping the first element, as follows:
std::vector<int> colourPos { 1, 2, 3 };
for (int p : colourPos | std::views::drop(1)) {
std::cout << "Pos = " << p << std::endl;
}
Output:
Pos = 2
Pos = 3
Code on Wandbox
Note: I would not recommend using a solution that contains begin() and/or end(), because the idea of a range-based for loop is to get rid of iterators. If you need iterators, then I would stick with an interator-based for loop.
Live demo link.
#include <iostream>
#include <vector>
#include <iterator>
#include <cstddef>
template <typename T>
struct skip
{
T& t;
std::size_t n;
skip(T& v, std::size_t s) : t(v), n(s) {}
auto begin() -> decltype(std::begin(t))
{
return std::next(std::begin(t), n);
}
auto end() -> decltype(std::end(t))
{
return std::end(t);
}
};
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : skip<decltype(v)>(v, 1))
{
std::cout << p << " ";
}
}
Output:
2 3 4
Or simpler:
Yet another live demo link.
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin()
{
return b;
}
T end()
{
return e;
}
};
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
}
Output:
2 3 4
Do this:
bool first = true;
for (int p : colourPos)
{
if (first)
{ first = false; continue; }
// ...
}