How to overload > operator?

How do I go about doing this? I've gotten some answers here on the forum but I'm having difficulty understanding it. I've even look at overloading different operators but to no avail. This was the code given to me by another member in the forum. Can someone help me understand it? There is additional code i can post.

1
2
3
4
5
bool operator < (const Card& lhs, const Card& rhs)//for sorting Card objects
{
    return lhs.m_itsSuit < rhs.m_itsSuit ||
        (!(rhs.m_itsSuit < lhs.m_itsSuit) && lhs.m_itsRank < rhs.m_itsRank);
}
these comparisons return bool
operator keyword is needed to overload an operator

which operator (this is literally the function name, and you can literally call it with some form of (I forget exactly, because you wouldn't normally do it) classname.<(duh,ugly); but its intent is to call with if (duh < lessugly) type syntax).

parameters, what to compare, left and right sides of the < here

return how to compare it... what exact conditions determine < for this data? Only you can define how your type (class) is going to work in terms of this one compared to that one...




It's actually pretty confusing logic... a excellent source of bugs.

Maybe it's easier to understand when written like this:
1
2
3
4
bool operator<(const Card& lhs, const Card& rhs) { 
  if (lhs.suit < rhs.suit) return true;
  return (lhs.suit == rhs.suit) && (lhs.rank < rhs.rank);
}
Last edited on
Canonical:
1
2
3
4
5
6
7
8
9
10
11
#include <tuple>

bool operator < ( const Card& lhs, const Card& rhs )
{
    const auto tie = [] ( const Card& c ) { return std::tie( c.m_itsSuit, c.m_itsRank ) ; };

    return tie(lhs) < tie(rhs) ;

    // note: for lexicographic comparison of just two members, std::make_pair would suffice
    // std::tie is more generic
}
@jonnin Thanks for the input!

@mbozzi That does seem to make more sense but is the second return going to be false? This is my first attempt at overloading an operator. Was going to look into some youtube videos too lol.

@JLBorges I'm not sure what std::tie is but I understand std::make_pair

Still a little confused but starting to clear up. Thank you for the answers! If anything else comes up to help clarify feel free to add!

Here is the full code i was given for the overload function if it helps:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <random>
#include <chrono>

enum Suit {Spades, Hearts, Clubs, Diamonds};//change as required;
std::ostream& operator << (std::ostream& os, const Suit& s)//for printing Suit objects
{
    switch(s)
    {
        case Spades: return os << "Spades";
        case Hearts: return os << "Hearts";
        case Clubs: return os << "Clubs";
        case Diamonds: return os << "Diamonds";
        default : return os << "";
    }
}
const std::string RANK[]  = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};

struct Card
{
    Suit m_itsSuit;
    std::string m_itsRank;
    Card(const Suit& itsSuit, const std::string& itsRank) :
        m_itsSuit(itsSuit), m_itsRank(itsRank){};
};
bool operator < (const Card& lhs, const Card& rhs)//for sorting Card objects
{
    return lhs.m_itsSuit < rhs.m_itsSuit ||
        (!(rhs.m_itsSuit < lhs.m_itsSuit) && (lhs.m_itsRank < rhs.m_itsRank));
}
std::ostream& operator << (std::ostream& os, const Card& c)//for printing Card objects
{
    os << c.m_itsSuit << " " << c.m_itsRank << "\n";
    return os;
}

int main()
{
    std::default_random_engine numGenerator(static_cast<unsigned int>(time(NULL)));
    std::uniform_int_distribution<int> rangeSuit(0, 3);
    std::uniform_int_distribution<int> rangeRank(0, 12);

    std::vector<Card> playerA{};
    std::vector<Card> playerB{};

    for (size_t i = 0; i < 5; ++i)
    {
        //create 2 hands of random cards
        playerA.emplace_back(Card(static_cast<Suit>(rangeSuit(numGenerator)), RANK[rangeRank(numGenerator)]));
        playerB.emplace_back(Card(static_cast<Suit>(rangeSuit(numGenerator)), RANK[rangeRank(numGenerator)]));
    }
    //sort the hands
    std::sort(playerA.begin(), playerA.end());
    std::sort(playerB.begin(), playerB.end());

    //print the hands
    std::cout << "Player A\n";
    for (const auto& elem : playerA)std::cout << elem ;
    std::cout << "\nPlayer B\n";
    for (const auto& elem : playerB)std::cout << elem;

    //check which hand has the lowest card
    if(playerA[0] < playerB[0])std::cout << "\nA\n"; else std::cout << "\nB\n";
}
Last edited on
> @JLBorges I'm not sure what std::tie is but I understand std::make_pair

In this case (just two members), we can use std::make_pair in place of std::tie

For two pairs lhs < rhs:
1. If lhs.first < rhs.first, returns true.
2. Otherwise, if rhs.first < lhs.first, returns false.
3. Otherwise, if lhs.second < rhs.second, returns true.
4. Otherwise, returns false.
http://en.cppreference.com/w/cpp/utility/pair/operator_cmp


Note that merely comparing the strings containing the rank "K" < "Q" or "A" < "3"
would not give the result that you expect. At the very least, it is dependant on the encoding in use by the implementation-defined character set.
Last edited on
@JLBorges what is.first in lhs.first and rhs.first?
That did help clear it up a lot more tho!

This is the if statement that works for my code if that helps: if(playerHand[i].cardNum < lowestCard.cardNum || (playerHand[i].suitStrength <= lowestCard.suitStrength && playerHand[i].cardNum <= lowestCard.cardNum))
Last edited on
I'm not sure what std::tie is

A k-tuple is a generalization of pair with k >= 0 elements. A tuple with two elements (a 2-tuple) is exactly a pair; a tuple with 3 elements (a 3-tuple) is a triplet, and so on for any k >= 0.
https://en.wikipedia.org/wiki/Tuple

std::tie creates a tuple of the appropriate size from (mutable references to) the arguments you give it. In the case above, it creates a 2-tuple from the arguments you give it, which is why it works equivalently to std::make_pair.

The interface is a little different for std::pair and std::tuple, because std::tuple is more general, but that doesn't matter here.

If you learn to write template metaprograms, you'll find plenty of techniques involving tuples. Those techniques were the main motivator for the addition of <tuple> to C++11.

-- In case I beat JLBorges to the punchline, first is the first element of the pair (in your case, the card's suit), and second is the second element of the pair (the card's rank). (std::pair is a class; those are its' members).

Last edited on
> This is the if statement that works for my code if that helps:
> if(playerHand[i].cardNum < lowestCard.cardNum ...

I presume that in your code, cardNum is a number, not a string.

Without changing anything else in the code, may be something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace
{
    // convert a rank string to a sanely comparable numeric value
    // the ranking order from low to high is the order in the RANK array
    int rank_str_to_rank( const std::string& rank_str )
    {
        const auto iter = std::find( std::begin(RANK), std::end(RANK), rank_str ) ;

        // if not found; return rank lower than that of any other card
        if( iter == std::end(RANK) ) return -1 ;

        else return iter - std::begin(RANK) ; // return its position in the array
    }
}

bool operator < ( const Card& lhs, const Card& rhs )
{
       const auto suit_rank_pair = [] ( const Card& c )
       { return std::make_pair( c.m_itsSuit, rank_str_to_rank(c.m_itsRank ) ) ; };

       return suit_rank_pair(lhs) < suit_rank_pair(rhs) ;
}

http://coliru.stacked-crooked.com/a/3de81f645cb04f75
@mbozzi Ohhh i see what a tie is. That would be better than using pairs right?
And I should have known what .first and .second were member functions since pairs were mentioned lol. Thanks for the reply! Cleared up the confusion when Tie.

@JLBorges yea, cardNum is an int. This is my class if it helps:
1
2
3
4
5
6
7
8
9
class CardTemplate
{
public:
    //Add another int for cardStrength and number all card based on str 0-51. 0 = 3 diamond and 51 = 2 spade
    std::string suit;
    int suitStrength;
    int cardNum;
    //potentially add string for 11+ cardNum instead of ints
};


Here is a search function I will be using the overloaded operator in. (Line 12)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CardTemplate searchLowestCard(std::vector<CardTemplate> playerHand)
{
    //set lowest card to test against
    CardTemplate lowestCard; //= playerHand[0];
    lowestCard.suit = "SATAN";
    lowestCard.suitStrength = 666;
    lowestCard.cardNum = 333;
    //loop to see who has the lowest car
    for(int i = 0; i < playerHand.size(); i++)
    {
        std::cout << "Hand: " << playerHand[i].suit << " : " << playerHand[i].cardNum << std::endl;
        if(playerHand[i].cardNum < lowestCard.cardNum || (playerHand[i].suitStrength <= lowestCard.suitStrength && playerHand[i].cardNum <= lowestCard.cardNum))
        {
            lowestCard = playerHand[i];
            std::cout << "Low Card: " << lowestCard.suit << " : " << lowestCard.cardNum << std::endl;
        }
    }
    std::cout << "END OF SEARCH" << std::endl;
    std::cout << "Lowest card is: " << lowestCard.suit << " : " << lowestCard.cardNum << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
    return lowestCard;
}


also the post (8:54PM) where I posted the code isn't my own so it's a little difficult to understand. But from my understanding is the cards are arranged and then ranked based on that arrangement however in my own personal program I let the user(s) arrange their own cards.

Also my project is split into three files. (class.cpp, class.h, main.cpp) For the overload do i need to declare it in my .h?
Last edited on
1
2
3
4
5
bool operator < (const CardTemplate& lhs, const CardTemplate& rhs)
{
    if (lhs.cardNum < rhs.cardNum) return true;
    return (lhs.cardNum == rhs.cardNum) && (lhs.suitStrength < rhs.suitStrength);
}


what is line 4 returning? True if that statement is correct?
Last edited on
Topic archived. No new replies allowed.