I am using a very simple structure, mapping, as defined below:
struct mapping{
int code;
string label;
bool operator<(const mapping& map) const {
return code < map.code;
}
bool operator==(const mapping& map) const {
return label.compare(map.label) == 0 ;
}
};
I would like to create a set of mapping ordered by their code. For that, I have overloaded the < operator. It works fine. I can insert some mappings with different labels without any problem.
The problem come when I try to insert mappings with the same code but different label. Actually, in the second step of the process, I have no idea if a mapping with same label has been previously inserted. So, I need to call the find() function to determine if it is the case or not. If no mapping with same label has been inserted, it is ok, I just need to insert this new one (but its code will be temporarily the same than one other mapping). If one mapping with the same labels exists, I just need to update its code. I though that overloading the == operator as I did should be enough but it is not the case as illustrated by the following code.
mapping m = {1,"xxx"};
mapping m2 ={1, "yyy"};
this->fn[0].insert(m);
set<mapping>::iterator itTmp;
itTmp = this->fn[0].find(m2);
if (itTmp != this->fn[0].end() ) {
cout << "m2 exists "<<endl;
if ( !(*itTmp == m2) ){
cout << "But it is different according to the definition of the == operator "<<endl;
}
}
Associated output is:
m2 exists
But it is different according to the definition of the == operator
How can I solve this issue and manage to deal with operators < and == with very different semantics? Ideally, I would like to avoid iterating on the whole set to look for mapping with the same label. Complexity of such a strategy is O(n) and n can be quite huge in my application. Similarly to the complexity of find() I would prefer a solution in O(log n).
Thanks,
Yoann
If a class can reasonably be sorted by more than one of its fields, it should not have relational operators (excepting
operator==andoperator!=) at all.Yes,
std::mapandstd::setby default usestd::lessas the comparator (which usesoperator<internally), but that’s just convenience so you don’t need to write a function object just to create aset<double>, wheredoublehas one canonical sort order (and therefore defines a (built-in)operator<).They also offer a comparator template argument, and you can and should use it to provide exactly the indexing that you need for that container (like a relational database). There are also containers (in boost) that maintain more than one index for a set of elements.
As an example, consider a
point2dclass:One could reasonably want to index a container of
point2ds by eitherxory, so following the above,point2dshouldn’t define anoperator<at all. To avoid having every user of the class inventing their own sorting function objects, they can be supplied together withpoint2d:Usage:
If you’re not afraid of templates, you can even templatise the relational operator, like this:
Usage: