Re: set::find with custom equality operator==
dragoncoder <pktiwary@gmail.com> writes:
Hi all, I have the following code.
// db_operators.h
#ifndef INCLUDED_DB_OPERATORS
#define INCLUDED_DB_OPERATORS
#include <cstring>
struct ecodb2{
unsigned long long id;
char code[21];
};
inline bool operator==(const ecodb2& lhs,
const ecodb2& rhs)
{
std::cout << "Some text" << std::endl;
return ((lhs.id == rhs.id) || !std::strcmp(lhs.code, rhs.code));
}
struct Compare
{
bool operator()(const ecodb2& lhs,
const ecodb2& rhs) const
{
bool retval = false;
if(lhs.id < rhs.id)
retval = true;
else if(lhs.id == rhs.id)
retval = std::strcmp(lhs.code, rhs.code);
return retval;
}
};
#endif
// main.cpp
#include <iostream>
#include <cstring>
#include <set>
#include <db_operators.h>
int main()
{
std::set<ecodb2, Compare> industry_codes;
^^^^^
<snip></snip>
}
While running this code, I expect to see Found in set (as either id or
code match meaning a perfect match) and also "Some text" being
printed, becasue set::find should call my custom operator==() function
to find a match but the output I get is "Not found in set" and also
"Some text" is not getting printed.
Please help.
I do not believe that std::set makes comparisons in the way you expect,
though I am not near my copy of the standard to check out the exact
details. Were you not to provide the second template parameter
`Compare', as you do above, then this would default to std::less. I would
suspect that set::find uses the same method as is used also for
ordering of items in the set, probably - where the default is used -
applying some such model of equality as:
!(rhs < lhs && lhs < rhs)
using std::less.
Thus, when leaving set to use the default comparator, std::less, you
would take control by implementing op< and not op==. However, in
providing your Compare class you are effectively saying that you want
this to play the role that std::less would have played otherwise,
effectively translating equality in this instance to something like:
!(aCompare(rhs, lhs) && aCompare(lhs, rhs))
Either way, and whatever the details are, it seems clear that set::find
is not using op== to test equality, and so your custom op== is not not
found because it is not a good match - it is not even looking for it.
Step through your code in a debugger and I am sure you will see that
set::find is using Compare::op() to handle equality testing. What is
more, take out the second template argument to the declaration of your
set, so that this becomes:
std::set<ecodb2> industry_codes;
and I think that you will find that you compiler complains about a
missing op<, not op==.
Try either something along the lines of this model:
#include <iostream>
#include <set>
struct A {
A(int i): i_(i) { }
int i_;
};
bool operator<(const A& lhs, const A& rhs)
{
return lhs.i_ < rhs.i_;
}
int main()
{
std::set<A> my_set;
my_set.insert(3);
my_set.insert(7);
my_set.insert(1);
std::set<A>::const_iterator i = my_set.find(A(3));
if (i != my_set.end())
std::cout << "Gotcha!\n";
else
std::cout << "Hhm...\n";
return 0;
}
or else replace op< with:
struct Compare {
bool operator()(const A& lhs, const A& rhs) {
return lhs.i_ < rhs.i_;
}
};
and use:
std::set<A, Compare> my_set;
which is closer to your original attempt.
I hope this helps, and is even vaguely correct.
Regards
Paul Bibbings
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]