I am confused about strict weak ordering and how to use it when defining operator<. I have a couple of structs:
struct Plane
{
std::string name;
int xrudder;
int yrudder;
int wingwidgets;
bool hasLegacyEngine;
};
struct Airport
{
bool securityCheck;
unsigned __int64 capacity;
std::vector<Plane> planes;
};
and I want to create a std::set of Airports. I need to define operator< which uses strict weak ordering but I don’t know exactly what that means and/or how to do it.
struct cmpless
{
bool operator()(const Airport& left, const Airport& right)
{
//?
}
};
std::set<Airport, cmpless> airportSet;
It doesn’t make sense that one airport is “less than” another. It only makes sense if the airports are equal based on their stats.
How can I be sure that my definition of operator< will follow strict weak ordering? How do I begin to think about defining operator< in a situation like this?
An example with an explanation would be great if possible!
If it “doesn’t make sense” for one
Airportto come before anotherAirportthen the use ofstd::set<Airport>doesn’t make sense, either. This container leverages the order amount elements to locate objects inO(log(n))operations (wherenis the size of the container). If you can identify object by identity only, the best complexity you can achieve isO(n). You can use a combination ofstd::find()orstd::find_if()and one of the sequence containers, e.g.,std::vector<Airport>orstd::deque<Airport>.Since you don’t need to define an order in terms of
operator<(), it may be reasonable to just bring theAirports into some order for the purpose of locating them in astd::set<Airport>which is done by using a different comparison function object thanstd::less<Airport>. The attribute you currently have in yourAirportobject don’t really look like suitable keys, though. In fact, they all look as if they would be mutable, i.e., you probably wouldn’t want astd::set<Airport>anyway because you can’t modify the elements in anstd::set<T>(well, at least, you shouldn’t; yes, I realize that you can play tricks withmutablebut this is bound to break the order of the elements).Based on this, I’d recommend to use a
std::map<std:string, Airport>: thestd::stringis used to identify the airport, e.g., using the airport codes like"JFK"for the John F. Kennedy Airport in New York or"LHR"for London Heathrow. Conveniently, there is already a strict weak order defined on strings.That said, to define a strict weak order on a set of objects
O, you need to a binary relationr(x, y)such that the following conditions hold for elementsx,y, andzfromO:r(x, x) == falser(x, y) == trueimpliesr(y, x) == falser(x, y) == trueandr(y, z) == trueimpliesr(x, z) == truer(x, y) == falseandr(y, x) == falseandr(y, z) == falseandr(z, y) == falseimpliesr(x, z) == falseandr(z, x) == falseThe first three should be simple enough. The last one is a bit odd at first but actually not that hard either: The basic idea is that the relation doesn’t entirely order element but groups them into equivalent classes. If you think of the relation
rto be “smaller than” it just says that if neitherxis smaller thanynoryis smaller thanx, thenxandyare equivalent. The incomparable elements are just equivalent.The standard containers work with a strict weak order but, e.g.,
std::set<T>andstd::map<K, V>keep just one version of equivalent keys. It is nice that this is sufficient but it is often simpler to just use a total order which is a strict weak order where for each pair of elementxandyeitherr(x, y) == trueorr(y, x) == true(but, due to the asymmetry not both).