Less than operator...

D

deancoo

Yet another question...

I have a container (vector say) containing my class objects. I've
overloaded the less than operator in my class definition to allow sorting
based on a certain attribute of the class. Now this is exactly what I need,
most of the time. I've found a couple of instances where I would like to be
able to sort (using the 'sort' algorithm) on a different attribute of my
class. Is there any other way I can take advantage of the 'sort' algorithm
in this new scenario? Advice?

Thanks for your help,

d
 
C

Chris Jefferson

deancoo said:
Yet another question...

I have a container (vector say) containing my class objects. I've
overloaded the less than operator in my class definition to allow sorting
based on a certain attribute of the class. Now this is exactly what I need,
most of the time. I've found a couple of instances where I would like to be
able to sort (using the 'sort' algorithm) on a different attribute of my
class. Is there any other way I can take advantage of the 'sort' algorithm
in this new scenario? Advice?

Fortunatly the writers of the STL thought of just this case. Therefore
most functions which use an ordering have an optional last parameter
which you can give an ordering function / object to!

So instead of doing (say) sort(v.begin(), v.end()) you do
sort(v.begin(),v.end(),ordering);

There are two main different ways of defining ordering. It can either be
a function:

bool ordering_function(const obj&a, const obj& b) { do stuff }

or a function object, which is defined by overloading operator(), so
something like:

struct ordering_object {
bool operator()(const obj& a, const obj& b) const
{ do stuff }
};


Then call:
sort(v.begin(),v.end(),ordering_function);
sort(v.begin(),v.end(),ordering_object());

note the () on the end of ordering_object. This creates a new
(temporary) ordering_object to pass to the function. You could just
create one instance of ordering_object and keep using that if you really
want, but it is actually usually more efficent to create a temporary one
like this (as it will be optimised away).

Also (slightly optimisy now) in general, the ordering_object version
will often be more efficent than the ordering_function (if you really
care why, I'll explain why below!)

Chris

Why is ordering_object more efficent than ordering_function?

Lets assume a) that we aren't going to inline the entire of sort
(reasonble, it's probably quite large) but that we could inline our
ordering predicate (they are usually quite small).

If you call sort(v.begin(),v.end(),ordering_function), the compiler will
generate an instansiation of sort which takes 2 iterators for v and a
boolean function that takes two objects and returns a bool. As the
instansation of sort isn't specific to the exact ordering_function, it
can't be inlined without much fiddling.

Now consider sort(v.begin(),v.end(),ordering_object()). This will
generate an instansation of sort which takes an 2 iterators for v and an
object of type ordering_object. There is only one possible thing
(assuming you defined as above) that can happen when you call operator()
on an object of type ordering_object, so in this case the ordering
function can be inlined. Of course this has the disadvantage a different
instansation of sort is generated for each ordering you use.
 
D

deancoo

Awesome. Thanks Chris.

Chris Jefferson said:
Fortunatly the writers of the STL thought of just this case. Therefore
most functions which use an ordering have an optional last parameter which
you can give an ordering function / object to!

So instead of doing (say) sort(v.begin(), v.end()) you do
sort(v.begin(),v.end(),ordering);

There are two main different ways of defining ordering. It can either be a
function:

bool ordering_function(const obj&a, const obj& b) { do stuff }

or a function object, which is defined by overloading operator(), so
something like:

struct ordering_object {
bool operator()(const obj& a, const obj& b) const
{ do stuff }
};


Then call:
sort(v.begin(),v.end(),ordering_function);
sort(v.begin(),v.end(),ordering_object());

note the () on the end of ordering_object. This creates a new (temporary)
ordering_object to pass to the function. You could just create one
instance of ordering_object and keep using that if you really want, but it
is actually usually more efficent to create a temporary one like this (as
it will be optimised away).

Also (slightly optimisy now) in general, the ordering_object version will
often be more efficent than the ordering_function (if you really care why,
I'll explain why below!)

Chris

Why is ordering_object more efficent than ordering_function?

Lets assume a) that we aren't going to inline the entire of sort
(reasonble, it's probably quite large) but that we could inline our
ordering predicate (they are usually quite small).

If you call sort(v.begin(),v.end(),ordering_function), the compiler will
generate an instansiation of sort which takes 2 iterators for v and a
boolean function that takes two objects and returns a bool. As the
instansation of sort isn't specific to the exact ordering_function, it
can't be inlined without much fiddling.

Now consider sort(v.begin(),v.end(),ordering_object()). This will generate
an instansation of sort which takes an 2 iterators for v and an object of
type ordering_object. There is only one possible thing (assuming you
defined as above) that can happen when you call operator() on an object of
type ordering_object, so in this case the ordering function can be
inlined. Of course this has the disadvantage a different instansation of
sort is generated for each ordering you use.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,201
Messages
2,571,052
Members
47,656
Latest member
rickwatson

Latest Threads

Top