problem on creating functor for std::sort

L

lok

i have a class:

template <class T1, class T2>
class CPairMapping {
public:
typedef std::pair<T1, T2> ValuePair_t;
typedef std::vector<ValuePair_t> ValueList_t;
typedef std::binary_function< ValuePair_t, ValuePair_t, bool> ValuePair_IsLess;

void SortAscend(const ValuePair_IsLess& isLess_) {
std::sort(Map.begin(), Map.end(), isLess_);
}

// skip other funciton like add,delete,lookup...
protected:
ValueList_t Map;
};

i want to sort the Map with a functor supplied by the caller of SortAscend()


i created a functor:
typedef COne2ManyMapping<int, int> INT2INTMap;
class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
public:
bool operator() (INT2INTMap::ValuePair_t lhs_,INT2INTMap::ValuePair_t rhs_)
{
return true;
}
};

up to now, no compile or link error
but if i call the SortAscend loke this:
INT2INTMap a;
a.AddEntry(1, 2);
a.AddEntry(3, 4);
a.SortAscend( INT2INTMap_IsLess() );

my vc++ 6.0 compiler reported:
error C2064: term does not evaluate to a function
see reference to function template instantiation '
void __cdecl std::_Unguarded_insert(
struct std::pair<int,int> *,
struct std::pair<int,int>,
struct std::binary_function<
struct std::pair<int,int>,
)
' being compiled

what is the problem ?
thx
 
R

Rolf Magnus

lok said:
i have a class:

template <class T1, class T2>
class CPairMapping {
public:
typedef std::pair<T1, T2> ValuePair_t;
typedef std::vector<ValuePair_t> ValueList_t;
typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
ValuePair_IsLess;

void SortAscend(const ValuePair_IsLess& isLess_) {
std::sort(Map.begin(), Map.end(), isLess_);
}

// skip other funciton like add,delete,lookup...
protected:
ValueList_t Map;
};

i want to sort the Map with a functor supplied by the caller of
SortAscend()


i created a functor:
typedef COne2ManyMapping<int, int> INT2INTMap;
class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
public:
bool operator() (INT2INTMap::ValuePair_t
lhs_,INT2INTMap::ValuePair_t rhs_)
{
return true;
}
};

up to now, no compile or link error
but if i call the SortAscend loke this:
INT2INTMap a;
a.AddEntry(1, 2);
a.AddEntry(3, 4);
a.SortAscend( INT2INTMap_IsLess() );

my vc++ 6.0 compiler reported:
error C2064: term does not evaluate to a function
see reference to function template instantiation '
void __cdecl std::_Unguarded_insert(
struct std::pair<int,int> *,
struct std::pair<int,int>,
struct std::binary_function<
struct std::pair<int,int>,

)
' being compiled

what is the problem ?

Your operator() is not const, so it isn't considered when std::sort
tries to call your function object.
 
L

lok

Rolf Magnus said:
Your operator() is not const, so it isn't considered when std::sort
tries to call your function object.

thx for your rely

i changed the operator() to this:
bool operator() (INT2INTMap::ValuePair_t lhs_,INT2INTMap::ValuePair_t rhs_)
const
{
return true;
}

the same error still occured
 
R

Rob Williscroft

lok wrote in
i have a class:

template <class T1, class T2>
class CPairMapping {
public:
typedef std::pair<T1, T2> ValuePair_t;
typedef std::vector<ValuePair_t> ValueList_t;
typedef std::binary_function< ValuePair_t, ValuePair_t, bool>
ValuePair_IsLess;

void SortAscend(const ValuePair_IsLess& isLess_) {
std::sort(Map.begin(), Map.end(), isLess_);

This isn't going to work std::binary_function< > isn't a binary function
its a base class for function object's that *only* supplies some
typedef's that describe the arguments and return values.

It does *NOT* have a virtual operator () (T const &, T const &) const.

You need to pass std::sort() a genuine functor.

std::less< ValuePair_t >() would be a good start.

}

// skip other funciton like add,delete,lookup...
protected:
ValueList_t Map;
};

i want to sort the Map with a functor supplied by the caller of
SortAscend()

You can a make SortAscend() a template member function (uppgrade your
compiler first) or make a functor with a virtual operator () ...

i created a functor:
typedef COne2ManyMapping<int, int> INT2INTMap;
class INT2INTMap_IsLess: public INT2INTMap::ValuePair_IsLess {
public:
bool operator() (INT2INTMap::ValuePair_t
lhs_,INT2INTMap::ValuePair_t rhs_) {
return true;
}
};

Make operator () a const member, also unless you like writing programmes
that hang or crash make it a valid Ordering function (model a < b) simply
returning true is nonsence.

std::sort(Map.begin(), Map.end(), INT2INTMap_IsLess() );
up to now, no compile or link error
but if i call the SortAscend loke this:
INT2INTMap a;
a.AddEntry(1, 2);
a.AddEntry(3, 4);
a.SortAscend( INT2INTMap_IsLess() );

my vc++ 6.0 compiler reported:
error C2064: term does not evaluate to a function

Yup std::binary_function said:
see reference to function template instantiation '
void __cdecl std::_Unguarded_insert(
struct std::pair<int,int> *,
struct std::pair<int,int>,
struct std::binary_function<
struct std::pair<int,int>,

)
' being compiled

HTH.

Rob.
 
L

lok

Rob Williscroft said:
lok wrote in

This isn't going to work std::binary_function< > isn't a binary function
its a base class for function object's that *only* supplies some
typedef's that describe the arguments and return values.

It does *NOT* have a virtual operator () (T const &, T const &) const.

You need to pass std::sort() a genuine functor.

std::less< ValuePair_t >() would be a good start.

std::sort(Map.begin(), Map.end(), std::less< ValuePair_t >() );

thx for your reply
i realize the problem (though not completely understand...)
but i need my own less comparison (that's why i want to create a
INT2INTMap_IsLess functor)
You can a make SortAscend() a template member function (uppgrade your
compiler first) or make a functor with a virtual operator () ...

i think this is the direction to go
can u explain further ? thx
Make operator () a const member, also unless you like writing programmes
that hang or crash make it a valid Ordering function (model a < b) simply
returning true is nonsence.

it just a test code to make the code more simple
 
L

lok

i modified the code as follow:
==================================
#include <vector>
#include <functional>
#include <string>
using std::string;

template <class T1, class T2 >
class CPairMapping {
public:
typedef std::pair<T1, T2 > ValuePair_t;
typedef std::vector<ValuePair_t > ValueList_t;

class ValuePair_IsLess {
public:
virtual bool operator() (const ValuePair_t& lhs_,const ValuePair_t&
rhs_) const;
};

void SortAscend(const ValuePair_IsLess* isLess_) {
std::sort(Map.begin(), Map.end(), *isLess_);
}
protected:
ValueList_t Map;
};

typedef CPairMapping< string, string > STR2STRMap;

class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess {
public:
bool operator() (const STR2STRMap::ValuePair_t& lhs_, const
STR2STRMap::ValuePair_t& rhs_) const {
return lhs_.first().size() < rhs_.first().size(); // #error line
}
};


int main() {
STR2STRMap a;
STR2STRMap_IsLess isLess;
a.SortAscend( &isLess );
return 0;
}
==================================
now vc compiler reported at #error line:
error C2064: term does not evaluate to a function
error C2228: left of '.size' must have class/struct/union type
error C2064: term does not evaluate to a function
error C2228: left of '.size' must have class/struct/union type

it seem compiler doesnt recognize STR2STRMap::ValuePair_t is a pair<
string, string > object

how can i solve this error ?
thx
 
R

Rob Williscroft

lok wrote in
i modified the code as follow:
==================================

Firstly my appologiess, I gave bad advise, makeing operator() virtual
was not a good idea as functors are mostly passed by value (so that
an ordinary function is also a functor), so slicing would occur
and what gets passed to std::sort is the base class with the
original operator ().

The following is a fix (of sorts) but it has no real advantage
over using a simple function pointer. Though it could if you need
to make the functor more complex.

#include <vector>
#include <functional>
#include <algorithm> // std::sort()
#include <string>

using std::string;

template <class T1, class T2 >
class CPairMapping
{
public:

typedef std::pair<T1, T2 > ValuePair_t;
typedef std::vector< ValuePair_t > ValueList_t;

class ValuePair_IsLess :
std::binary_function<
ValuePair_t const &, ValuePair_t const &, bool{
protected:

typedef
bool (*m_cmp_t)(
ValuePair_t const &lhs_, ValuePair_t const & rhs_
)
;
m_cmp_t m_cmp;

public:

ValuePair_IsLess( m_cmp_t cmp ) : m_cmp( cmp ) {}

bool operator() (
ValuePair_t const &lhs_, ValuePair_t const &rhs_
) const
{
return m_cmp( lhs_, rhs_ );
}
};

void SortAscend( ValuePair_IsLess isLess_ )
{
std::sort( Map.begin(), Map.end(), isLess_ );
}

protected:

ValueList_t Map;
};

typedef CPairMapping< string, string > STR2STRMap;

class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess
{
static bool cmp(
STR2STRMap::ValuePair_t const &lhs_,
STR2STRMap::ValuePair_t const &rhs_
)
{
return lhs_.first.size() < rhs_.first.size(); // #error line

// note the lack of .first().size() ..


}

typedef STR2STRMap::ValuePair_IsLess base_t;

public:

STR2STRMap_IsLess() : base_t( cmp ) {}
};


int main()
{
STR2STRMap a;
STR2STRMap_IsLess isLess;
a.SortAscend( isLess );
return 0;
}


Here's a simple function version, there is *alot* less cruft if
you really don't need it.


#include <vector>
#include <functional>
#include <algorithm> // std::sort()
#include <string>

using std::string;

template <class T1, class T2 >
class CPairMapping
{
public:

typedef std::pair<T1, T2 > ValuePair_t;
typedef std::vector< ValuePair_t > ValueList_t;

typedef bool (*ValuePair_IsLess)(
ValuePair_t const &lhs_, ValuePair_t const & rhs_
);

void SortAscend( ValuePair_IsLess isLess_ )
{
std::sort( Map.begin(), Map.end(), isLess_ );
}

protected:

ValueList_t Map;
};

typedef CPairMapping< string, string > STR2STRMap;

bool STR2STRMap_IsLess(
STR2STRMap::ValuePair_t const &lhs_,
STR2STRMap::ValuePair_t const & rhs_
)
{
return lhs_.first.size() < rhs_.first.size();
}

int main()
{
STR2STRMap a;
//STR2STRMap_IsLess isLess;
a.SortAscend( STR2STRMap_IsLess );
return 0;
}

Rob.
 
L

lok

after some little modification,
no compile, link or runtime error now
the code are follow:
=====================
#include <vector>
#include <functional>
#include <string>
using std::string;

template <class T1, class T2 >
class CPairMapping {
public:
typedef std::pair<T1, T2 > ValuePair_t;
typedef std::vector<ValuePair_t > ValueList_t;

class ValuePair_IsLess {
public:
virtual bool operator() (const ValuePair_t& lhs_,const ValuePair_t&
rhs_) const {
return lhs_ < rhs_;
}
};

void SortAscend(const ValuePair_IsLess& isLess_) {
std::sort(Map.begin(), Map.end(), isLess_);
}
protected:
ValueList_t Map;
};

typedef CPairMapping< string, string > STR2STRMap;

class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess {
public:
bool operator() (const STR2STRMap::ValuePair_t& lhs_, const
STR2STRMap::ValuePair_t& rhs_) const {
return lhs_.first.size() < rhs_.first.size();
}
};

int main() {
STR2STRMap a;
STR2STRMap_IsLess isLess;
a.SortAscend( &isLess );
}
=====================
but in debug mode, i found std::sort called the operator() of
CPairMapping::ValuePair_IsLess instead of the operator() of
STR2STRMap_IsLess
it seem the dynamic binding of virtual function failed to work
is this because a new CPairMapping::ValuePair_IsLess is created to
pass to the std::sort funciton ?

how to solve this problem ?

thx
 
R

Rob Williscroft

lok wrote in
after some little modification,
no compile, link or runtime error now
the code are follow: [snip]
but in debug mode, i found std::sort called the operator() of
CPairMapping::ValuePair_IsLess instead of the operator() of
STR2STRMap_IsLess
it seem the dynamic binding of virtual function failed to work
is this because a new CPairMapping::ValuePair_IsLess is created to
pass to the std::sort funciton ?

how to solve this problem ?

This works on the 3 conpilers I tried, (unfortunatly I haven't got
VC++ 6.0). See the comments inline:

#include <vector>
#include <functional>
#include <algorithm> /* forgot this again (std::sort) */
#include <string>
#include <iostream>

using std::string;

template <class T1, class T2 >
class CPairMapping
{
public:

typedef std::pair<T1, T2 > ValuePair_t;
typedef std::vector<ValuePair_t > ValueList_t;
typedef typename std::vector<ValuePair_t >::iterator iterator;


class ValuePair_IsLess
{
public:
virtual bool operator() (
const ValuePair_t& lhs_,const ValuePair_t& rhs_
) const
{
return lhs_ < rhs_;
}
};

void SortAscend(const ValuePair_IsLess& isLess_)
{
/* This is the trick,
force std::sort to take a Comparitor by reference
*/
std::sort<
iterator, ValuePair_IsLess const &
Map.begin(), Map.end(), isLess_
)
;
}

void add( T1 const &a, T2 const &b )
{
Map.push_back( ValuePair_t( a, b ) );
}

iterator begin() { return Map.begin(); }
iterator end() { return Map.end(); }

protected:

ValueList_t Map;
};


typedef CPairMapping< string, string > STR2STRMap;

class STR2STRMap_IsLess: public STR2STRMap::ValuePair_IsLess
{
public:
bool operator() (
const STR2STRMap::ValuePair_t& lhs_,
const STR2STRMap::ValuePair_t& rhs_
) const
{
return lhs_.first.size() < rhs_.first.size();
}
};


template < typename Iterator >
std::eek:stream &print_pairs( std::eek:stream &os, Iterator ptr, Iterator lim
)
{

if ( ptr != lim ) for (;;)
{
os << "( " << ptr->first << ", " << ptr->second << " )";
if (++ptr == lim ) break;
os << ", ";
}
return os;
}


int main()
{
STR2STRMap a;
STR2STRMap_IsLess isLess;

a.add( "2", "a" );
a.add( "1", "b" );

print_pairs( std::cerr, a.begin(), a.end() ) << "\n";

a.SortAscend( isLess ); /* pass by ref */

print_pairs( std::cerr, a.begin(), a.end() ) << "\n";
}




Rob.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top