So many asked this question and nobody came up with a satisfactory answer. Here is a std::sort helper that enables to sort two vectors simultaneously, taking into account the values of only one vector. This solution is based on a custom RadomIt (random iterator), and operates directly on the original vector data, without temporary copies, structure rearrangement or additional indices:
namespace std {
namespace sort_helper {
template <typename _Data, typename _Order>
struct value_reference_t;
template <typename _Data, typename _Order>
struct value_t {
_Data data;
_Order val;
inline value_t(_Data _data, _Order _val) : data(_data), val(_val) {}
inline value_t(const value_reference_t<_Data,_Order>& rhs);
};
template <typename _Data, typename _Order>
struct value_reference_t {
_Data* pdata;
_Order* pval;
value_reference_t(_Data* _itData, _Order* _itVal) : pdata(_itData), pval(_itVal) {}
inline value_reference_t& operator = (const value_reference_t& rhs) { *pdata = *rhs.pdata; *pval = *rhs.pval; return *this; }
inline value_reference_t& operator = (const value_t<_Data,_Order>& rhs) { *pdata = rhs.data; *pval = rhs.val; return *this; }
inline bool operator < (const value_reference_t& rhs) { return *pval < *rhs.pval; }
};
template <typename _Data, typename _Order>
struct value_iterator_t :
iterator< random_access_iterator_tag, value_t<_Data,_Order>, ptrdiff_t, value_t<_Data,_Order>*, value_reference_t<_Data,_Order> >
{
_Data* itData;
_Order* itVal;
value_iterator_t(_Data* _itData, _Order* _itVal) : itData(_itData), itVal(_itVal) {}
inline ptrdiff_t operator - (const value_iterator_t& rhs) const { return itVal - rhs.itVal; }
inline value_iterator_t operator + (ptrdiff_t off) const { return value_iterator_t(itData + off, itVal + off); }
inline value_iterator_t operator - (ptrdiff_t off) const { return value_iterator_t(itData - off, itVal - off); }
inline value_iterator_t& operator ++ () { ++itData; ++itVal; return *this; }
inline value_iterator_t& operator -- () { --itData; --itVal; return *this; }
inline value_iterator_t operator ++ (int) { return value_iterator_t(itData++, itVal++); }
inline value_iterator_t operator -- (int) { return value_iterator_t(itData--, itVal--); }
inline value_t<_Data,_Order> operator * () const { return value_t<_Data,_Order>(*itData, *itVal); }
inline value_reference_t<_Data,_Order> operator * () { return value_reference_t<_Data,_Order>(itData, itVal); }
inline bool operator < (const value_iterator_t& rhs) const { return itVal < rhs.itVal; }
inline bool operator == (const value_iterator_t& rhs) const { return itVal == rhs.itVal; }
inline bool operator != (const value_iterator_t& rhs) const { return itVal != rhs.itVal; }
};
template <typename _Data, typename _Order>
inline value_t<_Data,_Order>::value_t(const value_reference_t<_Data,_Order>& rhs)
: data(*rhs.pdata), val(*rhs.pval) {}
template <typename _Data, typename _Order>
bool operator < (const value_t<_Data,_Order>& lhs, const value_reference_t<_Data,_Order>& rhs) {
return lhs.val < *rhs.pval; }
template <typename _Data, typename _Order>
bool operator < (const value_reference_t<_Data,_Order>& lhs, const value_t<_Data,_Order>& rhs) {
return *lhs.pval < rhs.val; }
template <typename _Data, typename _Order>
void swap(value_reference_t<_Data,_Order> lhs, value_reference_t<_Data,_Order> rhs) {
std::swap(*lhs.pdata, *rhs.pdata);
std::swap(*lhs.pval, *rhs.pval); }
} // namespace sort_helper
} // namespace std
And this is an usage example that sorts both Names and Age based on Age values, employing standard std::sort:
char* Names[] = { "Karl", "Paul", "Martin", "Jennie" };
int Age[] = { 45, 14, 5, 24 };
typedef std::sort_helper::value_iterator_t<char*,int> IndexIt;
std::sort(IndexIt(Names, Age), IndexIt(Names+4, Age+4));
sorted to:
{ "Martin", "Paul", "Jennie", "Karl" };
{ 5, 14, 24, 45 };
Code tested on Visual Studio 2017 and GCC 5.4.0.