Re: Problems with std::less
On 2007-06-10 14:28, ek wrote:
I have the following class:
template<typename I>
class test {
public:
test(I i) : pp(i) {}
I getpp() const {
return pp;
}
void setpp(I i) {
pp = i;
}
bool operator<(const test& t) const {
return (this < &t);
}
private:
I pp;
};
In main I do:
int main(){
test<int> t1(1);
test<int> t2(2);
std::less<test<int> > C;
std::cout << "C(t1,t2) = " << C(t1,t2) << std::endl;
std::cout << "C(t1,t1) = " << C(t1,t1) << std::endl;
return 0
}
But it prints 0 in both cases. How do I compare objects? When I supply
these objects to a std::set the '<' operator in my class should work
so at the moment the tree would not be balanced correctly.
To compare two objects you have to decide what the properties that
defines the object are, and then how you based on this order objects. In
the code above you have decide that the address of the object determines
which is the smallest one. This is generally a bad idea since the result
of comparing two objects might not be the same as when two copies of
them are compared.
In your case the natural thing to compare would be the value of pp, so
change your operator < to:
bool operator<(const test& t) const {
return (pp < t.pp);
}
and you'll get the expected results when you run the program.
Another thing. I don't see the point in using 'C' I can just use the
operator '<' directly:
std::cout << "t1 < t2 = " << (t1 < t2) << std::endl;
std::cout << "t1 < t1 = " << (t1 < t1) << std::endl;
which gives the same result, so why go through the extra layer with
using std::less which just calls the '<' anyway instead of just
calling '<' directly?
The idea of using std::less in a container is that the user can specify
how they want their objects compared, if we take std::set as an example
it has the following signature (from VC++2005):
template <class Key,
class Traits=less<Key>,
class Allocator=allocator<Key>
>
class set;
So, Key is the type of object you want to store in the set, Traits tells
you how to compare two objects, and Allocator how they are allocated. As
you can see the default comparator is std::less, which means that the
objects < operator will be used, but you can change this to std::greater
to use the objects' > instead, or you can create a specialized one that
compares the results of calling foo(5) on the objects.
If you add an operator > like this to test:
bool operator>(const test& t) const {
return (this->pp > t.pp);
}
And take a look at this code which implements a class that keeps a copy
of an object:
template<class T, class Comp>
class KeepOne
{
T theOne;
Comp C;
public:
KeepOne(T init) : theOne(init) {}
void insert(T t)
{
if (C(t, theOne))
theOne = t;
}
T& get() { return theOne; }
};
int main()
{
test<int> t1(1);
test<int> t2(2);
KeepOne<test<int>, std::less<test<int> > > k(t2);
k.insert(t1);
std::cout << k.get().getpp();
}
As you can see, when you insert() into the KeepOne object it will only
keep one object and the one that it keeps is determined by the
comparator used. Replace std::less<test<int> > with
std::greater<test<int > > and you'll see that it will keep t2 instead of t1.
--
Erik Wikstr?m