0

Yes, I know this is a repeat question and I already know that the anwser im looking for is here:

Sorting a vector of objects by a property of the object

However I have problems converting this to my own code. I'm looking at this code snippet from the above question:

struct SortByX
{
    bool operator() const(MyClass const& L, MyClass const& R) {
        return L.x < R.x;
    }
};

std::sort(vec.begin(), vec.end(), SortByX();

What I do not understand is what is being represented by MyClass const & L, and MyClass const & R. And I am not grasping how I can apply this to my code.

To give a bit more detail I am putting 3 sort methods into a wrapper class of a vector of objects that have parameters of (string, double, double, double, bool). And the over all goal is to sort the vector by the string, the bool and any one out of the 3 doubles.

This is the lastest version I have:

void StationVector::sortByGrade(int kindOfGas) {
struct SortByGrade {
    int kindOfGas;

    SortByGrade(int kindOfGas) :
            kindOfGas(kindOfGas) {
    }

    bool operator()(GasStation const &L, GasStation const & R) const {
        return L.getPrice(kindOfGas) < R.getPrice(kindOfGas);
    }
};

std::sort(localStations.begin(), localStations.end(),
        SortByGrade(kindOfGas));
}

the line SortByGrade(kindOfGas)) gives me the following error:

no matching function for call to `sort(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, model::StationVector::sortByGrade(int)::SortByGrade)'

Community
  • 1
  • 1
Noob
  • 145
  • 2
  • 9

2 Answers2

2

SortByX is a binary predicate functor. Binary predicate means it takes two arguments and returns a boolean. Functor means it's instances are callable. For example:

MyClass a = ....;
MyClass b = ....;
SortByX comp;
bool flag = comp(a,b); // call this SortByX instance with two MyClass instances

Now, std::sort will internally use a copy of the instance of SortByX that you pass it in order to perform the comparisons between the elements of a std::vector<MyClass> needed to sort that vector.

std::vector<MyClass> v;
// fill the vector with MyClass objects
std::sort(v.begin(), v.end(), SortByX()); // sort the vector using a SortByX instance for comparisons

Note: for this to work, the binary predicate must implement strict weak ordering.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • So If im reading this correctly This explains how SortByX works but now how to implement it. – Noob Feb 10 '13 at 23:41
  • @Nood the `SortByX` implementation that you posted shows you exactly how this thing can be implemented. Looking at your edit, it looks like you got it. – juanchopanza Feb 10 '13 at 23:44
1

What I do not understand is what is being represented by MyClass const & L, and MyClass const & R.

L and R, in this case are two items (instances of your class MyClass) from the container that are being compared, with L on the left of the less-than operator and R on the right. They are passed in by const-reference.

And I am not grasping how I can apply this to my code.

In your own bool operator() const(MyClass const& L, MyClass const& R), you need to compare the three data members you mention in your question, vitally remembering to apply strict weak ordering. Return true if L is "less than" R and false otherwise.


Following updates to the question...

It looks like you wish to pass a variable into your functor. You do this by creating a constructor, like this SSCCE (which compiles here):

#include <algorithm>
#include <vector>

namespace model {

struct GasStation
{
    double getprice(int kindOfGas) const
    {
        return kindOfGas;
    }
};

struct StationVector
{
    std::vector<GasStation> localStations;

    struct SortByGrade
    {
        int kindOfGas_;
        SortByGrade(int kindOfGas)
            :kindOfGas_(kindOfGas)
        {
        }

        bool operator() (GasStation const &L, GasStation const & R) const
        { 
            // You'll need other comparisons here, but this is a good start...
            return L.getprice(kindOfGas_) < R.getprice(kindOfGas_); 
        }
    };

    void sortByGrade(int kindOfGas) 
    {
        std::sort(localStations.begin(), localStations.end(), SortByGrade(kindOfGas));
    }
};

}

int main()
{
    model::StationVector sv;
    sv.sortByGrade(0);
}

Note: The const qualifier comes after the argument list and not after the method name.

Also, please don't put the entire method on one line, it makes it very difficult to read.

Community
  • 1
  • 1
johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • Im still not understanding how to implement the code properly. Can you show me an example – Noob Feb 10 '13 at 23:45
  • Trying the above example is getting an error stating "passing `const model::GasStation' as `this' argument of `double model::GasStation::getPrice(int)' discards qualifiers" I'm not sure what thats trying to tell me. – Noob Feb 11 '13 at 02:03
  • `double model::GasStation::getPrice(int)` should be declared `const` (unless it somehow modifies the state of the object, in which case it's not likely to be a good candidate to use in a comparator). – johnsyweb Feb 11 '13 at 02:07
  • Meaning? I changed double GasStation::getPrice(int){ to double const GasStation::getPrice(int){ That didn't change anything. Did i misunderstand what you were trying to say? – Noob Feb 11 '13 at 02:18
  • As I wrote earlier, "Note: The const qualifier comes after the argument list and not after the method name.". `double GasStation::getPrice(int) const`. – johnsyweb Feb 11 '13 at 02:20
  • Ok thanks. I very new to C++ this is only my second attempt at it. I finally got the struct code to work except now the actual sort call has an error saying "no matching function call...." is that a #include problem? right now im using do I need something else to make it recognize the call? – Noob Feb 11 '13 at 02:29
  • It depends on what it says is missing and where it is declared! – johnsyweb Feb 11 '13 at 02:31
  • It delclared it the header file of the class and here is the whole error message `no matching function for call to sort(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, model::StationVector::sortByGrade(int)::SortByGrade)` – Noob Feb 11 '13 at 02:39
  • Can you please paste the latest version of your `sortByGrade(int)` method as an addition to your question. I cannot debug like this. – johnsyweb Feb 11 '13 at 02:44
  • Well crap. I all i had to do for awhile now is move the struct out of the method I was trying to use it in. I got it working now. Again thank you for the help. I doubt I would have figured any of this out by myself. – Noob Feb 11 '13 at 03:37
  • Moving the `struct` out of the method will make it easier to reuse and to test. It may also prevent "shadowing" variables. Glad I've helped you but ***don't forget the strict weak ordering***. – johnsyweb Feb 11 '13 at 03:40
  • Actually one last thing on that if when im dealing with bools I know i can't say bool1 < bool2. But really It dose not matter if the false or the true comes first so can't I just say `return bool1`? As long as it sorts all of one the all of the other then its fine. Will that do that? – Noob Feb 11 '13 at 04:01
  • [You *can* compare `bool`s with `<`](http://stackoverflow.com/questions/11951729/ordering-of-boolean-values)! And **to ensure strict weak ordering, it does matter**, so you will probably need a comparison like: `if (L.loyalty_card != R.loyalty_card) return L.loyalty_card < R.loyalty_card;` (just making up a `bool` value there)! – johnsyweb Feb 11 '13 at 04:21
  • I just tried that and got an error. But will the way I suggested work? (By the way I'm programming blind here, because I can't run/test any code. Something somewhere on my comp is messed up and i don't have time to try to fix it) – Noob Feb 11 '13 at 04:24
  • 1
    The best advice I can give at this time is stop programming until you have fixed your environment and you can run and test your code. Here is an example of sorting including the `bool` values: http://ideone.com/lmyqOi – johnsyweb Feb 11 '13 at 05:04