RedLeader
RedLeader

Reputation: 657

C++: Sort into new array based on template field

I'm looking for a solution to sort a global array into new structure, based on a variable field:

struct OutputStruct {
  int iDestId,
  ...
  }

struct GlobalData {
  int A,
  int B,
  int C,
  int iDestId
}

template < typename FIELD > 
void SortByField( OutputStruct *& pOutputStruct, int iNumElements, FIELD glbArray::*field )
{
  // Sort the glblArray by the FIELD element, and output the order of iDestId's to OutputStruct.
}

For example:

GlobalData glblArray[4] = {
   ( 1, 2, 3, 40 )
   ( 0, 0, 0, 32 )
   ( 2, 2, 1, 78 )
   ( 0, 5, 9, 11 ) }

OutputStruct outputStruct[10] = {0};

SortByField( outputStruct, 4, &GlobalData::C );

Would yield:

outputStruct = { (32, ...) , (78, ...), (40, ...), (11, ...) }

Upvotes: 0

Views: 61

Answers (1)

WhozCraig
WhozCraig

Reputation: 66224

I'm not going to even attempt to adapt something to the fantasy code you posted, primarily because none of it compiles anyway. But the hitch that seems to be holding you back is understanding how the member pointer operators work.

Below is a simple example of sorting a sequence of structures, each time by a separate template comparator that is constructed from provided arguments. The results are posted after each sort, with each sequence reflecting the order of the sorted member after re-ordering.

#include <iostream>
#include <algorithm>
#include <type_traits>
#include <iterator>

struct GlobalData 
{
    std::string name;
    int A,B,C;
};

template<class Field>
struct GlobalDataFieldCmp
{
    Field GlobalData::*mvar;

    GlobalDataFieldCmp(Field GlobalData::*mvar) 
        : mvar(mvar) 
    {
    }
};

template<class Iter, class Field>
void sort_by_field(Iter beg, Iter end, Field std::iterator_traits<Iter>::value_type::* const field)
{
    auto cmp = [field](
        typename std::iterator_traits<Iter>::value_type const& lhs,
        typename std::iterator_traits<Iter>::value_type const& rhs)->bool
    {
        static std::less<Field> is_less;
        return is_less(lhs.*field, rhs.*field);
    };

    std::sort(beg, end, cmp);
}

int main()
{
    GlobalData gd[] = 
    {
          { "a", 3,2,1 }
        , { "b", 2,1,2 }
        , { "c", 1,3,3 }
    };

    sort_by_field(std::begin(gd), std::end(gd), &GlobalData::A);
    for (auto& x : gd)
        std::cout << x.name << ' ';
    std::cout << '\n';

    sort_by_field(std::begin(gd), std::end(gd), &GlobalData::B);
    for (auto& x : gd)
        std::cout << x.name << ' ';
    std::cout << '\n';

    sort_by_field(std::begin(gd), std::end(gd), &GlobalData::C);
    for (auto& x : gd)
        std::cout << x.name << ' ';
    std::cout << '\n';
}

Output

c b a 
b a c 
a b c 

Now, what you want to do with this is another issue. If you want the resulting sort separated from the original data, either make a copy or sort a sequence of pointers and adapt the code. Regardless, this ultimately is an example of how to use the member pointer operator .*, and hopefully that much is clear.

Upvotes: 3

Related Questions