By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,320 Members | 1,893 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,320 IT Pros & Developers. It's quick & easy.

Making a class that accepts a user-defined STL coparison function

P: n/a
I have a container that I wish to allow the user to specify a custom
comparison method very similar to std::less. However, I want it to
function more like memcmp (returning -1 0 1), and I want to be able to
vary the fields that are compared. The example below shows how I'd
like it to fit together.

struct fields
{
fields( int f1, int f2, int f3 ){ m_f[0] = f1; m_f[1] = f2; m_f[2]
= f3; }
int m_f[3];
};

template< typename T >
class Foo
{
public:
Foo( const T & t ) : m_t( t ){ }
int dosomething( const T & t )
{
// error: want to compare t by any of the 3 fields. the method
// passed in should handle which fields are compared.
if( t < m_t ) return -1;
else if( t > m_t ) return 1;
else return 0;
}
protected:
const T m_t;
};

int main(int argc, char* argv[])
{
Foo< fields > foo( fields( 3, 2, 1 ) );
foo.dosomething( fields( 1, 2, 3 ) );
return 0;
}

Jul 23 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
"titancipher" <ja***********@gmail.com> wrote in message
news:11*********************@z14g2000cwz.googlegro ups.com...
I have a container that I wish to allow the user to specify a custom
comparison method very similar to std::less. However, I want it to
function more like memcmp (returning -1 0 1), and I want to be able to
vary the fields that are compared. The example below shows how I'd
like it to fit together.

struct fields
{
fields( int f1, int f2, int f3 ){ m_f[0] = f1; m_f[1] = f2; m_f[2]
= f3; }
int m_f[3];
};


If you need to compare objects of type 'fields' define comparison operators
for this type:

bool operator < (const fields& l, const fields& r)
{
/* return whatever logic comes here; */
}
bool operator > (const fields& l, const fields& r)
{
/* return whatever logic comes here; */
}
Regards,
Janusz
Jul 23 '05 #2

P: n/a
titancipher wrote:
I have a container that I wish to allow the user to specify a custom
comparison method very similar to std::less. However, I want it to
function more like memcmp (returning -1 0 1), and I want to be able to
vary the fields that are compared. The example below shows how I'd
like it to fit together.

struct fields
{
fields( int f1, int f2, int f3 ){ m_f[0] = f1; m_f[1] = f2; m_f[2]
= f3; }
int m_f[3];
};

template< typename T >
class Foo
{
public:
Foo( const T & t ) : m_t( t ){ }
int dosomething( const T & t )
{
// error: want to compare t by any of the 3 fields. the method
// passed in should handle which fields are compared.
if( t < m_t ) return -1;
else if( t > m_t ) return 1;
else return 0;
}
protected:
const T m_t;
};

int main(int argc, char* argv[])
{
Foo< fields > foo( fields( 3, 2, 1 ) );
foo.dosomething( fields( 1, 2, 3 ) );
return 0;
}


You want to make your "dosomething" function a member template. For
example:

template <class Compare>
int dosomething( const T & t, const Compare & comp)
{
int result = comp(t, m_t) ;

if (result == 1)
std::cout << "greater" << std::endl ;
else if (result == -1)
std::cout << "less" << std::endl ;
else
std::cout << "equal" << std::endl ;
}

Then your user defined comparison objects will look something like this.

class compare_field
{
unsigned n ; // field to compare
public :
compare_field(unsigned n) : n(n) {}

int operator()(const fields &f1, const fields &f2) const
{
if (f1.m_f[n] < f2.m_f[n])
return -1 ;
else if (f1.m_f[n] > f2.m_f[n])
return 1 ;
else
return 0 ;
}
} ;
You may then call dosomething in a manner similar to this :

Foo< fields > foo( fields( 3, 2, 1 ) );
foo.dosomething( fields( 1, 2, 3 ), compare_field(0) );
foo.dosomething( fields( 1, 2, 3 ), compare_field(1) );
foo.dosomething( fields( 1, 2, 3 ), compare_field(2) );

-Alan
Jul 23 '05 #3

P: n/a
Hi Alan,
Thanks, what you describe would work. However, I was looking to
provide a more STL-like method. If you look at std::map, std::set,
etc., the method std::less is used as a default argument in the
template specification. What you propose would require passing a
compare_field(0) for each insert (i.e. 'dosomething').

I've done a little more thinking about it, and have a solution. I'll
post it. First, I create a class much like std::less called compare:

template< typename T >
class compare : public std::binary_function< T, T, int >
{
public:
compare(){ }
public:
bool operator()( const T & lhs, const T & rhs ) const
{
if( lhs < rhs ) return -1;
else if( lhs < rhs ) return 1;
else return 0;
}
};

Then, I change Foo to use the binary function 'compare' by default:

template< typename T, class C = compare< T > >
class Foo
{
public:
Foo( const T & t ) : m_t( t ){ }

int foocmp( const T & t )
{
int c = compare( t, m_t );
if( c < 0 ) return -1;
else if( c > 0 ) return 1;
else return 0;
}
protected:
const T m_t;
const C compare;
};

Then, because the default compare is not adequate to compare my fields
class (it does not compare individual fields), I write a custom compare
per-field. Field 0 compare is below:

class cmp_field_0 : public std::binary_function< fields, fields, int >
{
public:
cmp_field_0() : m_n( 0 ) { }
public:
int operator()( const fields & lhs, const fields & rhs ) const
{
if( lhs.m_f[ m_n ] < rhs.m_f[ m_n ] ) return -1;
else if( lhs.m_f[ m_n ] < rhs.m_f[ m_n ] ) return 1;
else return 0;
}
private:
int m_n;
};

The usage is now:

Foo< fields, cmp_field_0 > foo( fields( 3, 2, 1 ) );
foo.dosomething( fields( 1, 2, 3 ) );

However, I would have to create a cmp_field_1, cmp_field_2, etc., and
that's that's still not great. I can then change the cmp_field to
include another template argument to indicate the field to test:

template< int F >
class cmp_field : public std::binary_function< fields, fields, int >
{
public:
cmp_field() : m_n( F ) { }
public:
int operator()( const fields & lhs, const fields & rhs ) const
{
if( lhs.m_f[ m_n ] < rhs.m_f[ m_n ] ) return -1;
else if( lhs.m_f[ m_n ] < rhs.m_f[ m_n ] ) return 1;
else return 0;
}
private:
int m_n;
};

The usage is now:

Foo< fields, cmp_field< 0 > > foo( fields( 3, 2, 1 ) );
foo.dosomething( fields( 1, 2, 3 ) );

The above achieves making a STL-like comparison operator to compare
different fields. However, I'd still be interesting in seeing someone
else's angle on this.

Kind Regards,
Jamie

Jul 23 '05 #4

P: n/a
Sorry, the default compare class is:
template< typename T >
class compare : public std::binary_function< T, T, int >
{
public:
compare(){ }
public:
int operator()( const T & lhs, const T & rhs ) const
{
if( lhs < rhs ) return -1;
else if( lhs < rhs ) return 1;
else return 0;
}
};

Not 'bool' like previously specified.

Jul 23 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.