operator< for algorithms

H

Hicham Mouline

Hello,

namespace NS1 { namespace NS2 {

template <typename T1, typename T2>
class C {
public:
typedef T1::xType xType;
typedef T1::yType yType;
....
private:
typedef std::pair< xType, yType> EntryType;
boost::array< EntryType , size > ContainerType;
....
};
....
}}

I need to use std::lower_bound and sorting algorithms on my ContainerType.

Where (which namespace) and how can I define the operator< comparing 2
EntryType
for the std:: algorithms to use that operator?

Note I use these std::algorithms only in member functions of the C template.
So I wish to define the operator< in a way that is specific and visible only
to C template.

best regards,
 
V

Victor Bazarov

Hicham said:
namespace NS1 { namespace NS2 {

template <typename T1, typename T2>
class C {
public:
typedef T1::xType xType;
typedef T1::yType yType;
...
private:
typedef std::pair< xType, yType> EntryType;
boost::array< EntryType , size > ContainerType;
....
};
...
}}

I need to use std::lower_bound and sorting algorithms on my ContainerType.

Where (which namespace) and how can I define the operator< comparing 2
EntryType
for the std:: algorithms to use that operator?

Anywhere appropriate. Any namespace/class where your compiler is
capable of finding it.
Note I use these std::algorithms only in member functions of the C template.
So I wish to define the operator< in a way that is specific and visible only
to C template.

Have you tried defining it as a static member of the C template?

Post the rest of your code, with only the operator< missing, and we can
probably figure it out. I am just too lazy to provide all the necessary
driver code for what you've described, I consider it your job if you
want my help. Sorry, such a PITA I am.

V
 
H

Hicham Mouline

Victor Bazarov said:
Anywhere appropriate. Any namespace/class where your compiler is capable
of finding it.


Have you tried defining it as a static member of the C template?

Post the rest of your code, with only the operator< missing, and we can
probably figure it out. I am just too lazy to provide all the necessary
driver code for what you've described, I consider it your job if you want
my help. Sorry, such a PITA I am.

V
Not at all. Thank you for your contrib!

I put the code here
http://codepad.org/Gwfm36GL

It fails to compile under g++4
"operator< needs to be must be either a non-static member function or a
non-member function"

if it is member non-static, it is interpreted as applying to C<T1,T2> not to
EntryType

As EntryType is private, I don't know how to define outside of C<T1,T2>

rds,
 
V

Victor Bazarov

Hicham said:
Not at all. Thank you for your contrib!

I put the code here
http://codepad.org/Gwfm36GL

It fails to compile under g++4
"operator< needs to be must be either a non-static member function or a
non-member function"

if it is member non-static, it is interpreted as applying to C<T1,T2> not to
EntryType

As EntryType is private, I don't know how to define outside of C<T1,T2>

I managed to make your code from the 'codepad.org' to compile when I
removed the operator< definition from the 'C' template (it wasn't the
brightest suggestion, I guess) and put it right after the 'C' as this:

template<class T, class U>
bool operator<(const typename C<T,U>::EntryType& lhs,
const typename C<T,U>::EntryType& rhs)
{
return true;
}

I am not sure how to try it with Comeau online.

V
 
H

Hicham Mouline

Victor Bazarov said:
I managed to make your code from the 'codepad.org' to compile when I
removed the operator< definition from the 'C' template (it wasn't the
brightest suggestion, I guess) and put it right after the 'C' as this:

template<class T, class U>
bool operator<(const typename C<T,U>::EntryType& lhs,
const typename C<T,U>::EntryType& rhs)
{
return true;
}
It is strange that this compiles.
EntryType is private, why does operator< outside manage to access it?

Let me now see if that operator< is really used by lower_bound,

rds,
 
V

Victor Bazarov

Hicham said:
It is strange that this compiles.
EntryType is private, why does operator< outside manage to access it?

It is quite possible that since all instantiations of that operator are
made from inside a member function of 'C', where access to 'EntryType'
is granted, the compiler considers it an implicit permission...

V
 
H

Hicham Mouline

Victor Bazarov said:
It is quite possible that since all instantiations of that operator are
made from inside a member function of 'C', where access to 'EntryType' is
granted, the compiler considers it an implicit permission...
It doesn't seem to work

template<class T, class U>
bool operator<(const typename C<T,U>::EntryType& lhs,
const typename C<T,U>::EntryType& rhs)
{
std::cout<< "called" <<std::endl;
return true;
}

never prints anything

I just realized c++03 defines operators< for std::pair<> in std.

Maybe I need to override those

rds,
 
H

Hicham Mouline

Hicham Mouline said:
It doesn't seem to work

template<class T, class U>
bool operator<(const typename C<T,U>::EntryType& lhs,
const typename C<T,U>::EntryType& rhs)
{
std::cout<< "called" <<std::endl;
return true;
}

never prints anything

I just realized c++03 defines operators< for std::pair<> in std.

Maybe I need to override those

rds,

still doesn't wor, strange
http://codepad.org/h9uFoI1I

rds,
 
V

Victor Bazarov

Hicham said:
still doesn't wor, strange
http://codepad.org/h9uFoI1I

Hm...

I tried redefining your type 'EntryType' as derived from 'std::pair',
and it didn't help either.

I don't know. Apparently the compiler is unable to resolve it (or
instantiate the template) and if falls back on what it can do, the
operator < for std::pair...

I think you should resort to a named function/functor:

template<class T, class U>
bool op_less(const typename NS1::NS2::C<T,U>::EntryType& lhs,
const typename NS1::NS2::C<T,U>::EntryType& rhs)
{
std::cout<< "called" <<std::endl;
return true;
}

....
template<typename T1, typename T2>
void C<T1, T2>::FindX(xType x) const
{
std::cout<< "inside Find"<<std::endl;
if ( op_less<T1,T2>(mContainer[0], mContainer[1]) )
{
std::cout<<" 0 < 1 "<<std::endl;
}
if ( op_less<T1,T2>(mContainer[1], mContainer[0]) )
{
std::cout<<" 1 < 0 "<<std::endl;
}
}


V
 
J

James Kanze

namespace NS1 { namespace NS2 {
template <typename T1, typename T2>
class C {
public:
typedef T1::xType xType;
typedef T1::yType yType;

You are, presumably, using an older compiler. The above
shouldn't compile (and won't with most newer compilers); you
need an additional typename.
...
private:
typedef std::pair< xType, yType> EntryType;
boost::array< EntryType , size > ContainerType;
....

I need to use std::lower_bound and sorting algorithms on my
ContainerType.

That could be tricky if either xType or yType don't support
comparison. And if they both support <, then your EntryType
already has an operator<, which you don't want to change (since
that would confuse any reader). And if EntryType supports <,
then boost::array should as well. (I've not verified the
latter, but as far as I know, boost::array adheres to the
requirements of a container in the standard.)
Where (which namespace) and how can I define the operator<
comparing 2 EntryType for the std:: algorithms to use that
operator?
Note I use these std::algorithms only in member functions of
the C template. So I wish to define the operator< in a way
that is specific and visible only to C template.

That's a tricky one. The correct answer is: in the namespace
where one of the actual types was defined, i.e. where the T1 of
the instantiation was defined. Except that, as mentionned, you
can't define an operator< for EntryType or ContainerType, since
the standard already defines one.

If the standard operator isn't appropriate, then There are two
simple solutions:

-- Drop std::pair. Using it is probably an error anyway---do
the two components really have a semantic of "first" and
"second"? (There are cases where they do, but in those
cases, the standard operator is appropriate.) Just define a
nested class (or simply a struct) with the two types, and
the operator< defined as you want.

-- Don't use <. All of the functions involving order (sort,
lower_bound, etc.) have a overload taking an additional
argument specifying the ordering function. So you provide a
nested class (fuctional object) which defines the ordering
you want, and pass an instance of it to the function each
time.
 
H

Hicham Mouline

-- Don't use <. All of the functions involving order (sort,
lower_bound, etc.) have a overload taking an additional
argument specifying the ordering function. So you provide a
nested class (fuctional object) which defines the ordering
you want, and pass an instance of it to the function each
time.


Thanks. I went with the 2nd solution

inner class
// EntryType comparison predicate
struct EntryTypeLess : public std::binary_function<EntryType, EntryType,
bool> {
bool operator() ( const EntryType& lhs, const EntryType& rhs ) const
{
return lhs.first < rhs.first;
}

which I then use as the Cmp in lower_bound, and I use once explicitly.

best regards,
 

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
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top